diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/test/core/Circle.js b/test/core/Circle.js
index 183f98f..f621992 100644
--- a/test/core/Circle.js
+++ b/test/core/Circle.js
@@ -53,6 +53,10 @@
expect(circ1.contains(10, 16)).to.be.false;
expect(circ1.contains(11, 15)).to.be.false;
expect(circ1.contains(0, 0)).to.be.false;
+
+ const circ2 = new PIXI.Circle(10, 10, 0);
+
+ expect(circ2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/test/core/Circle.js b/test/core/Circle.js
index 183f98f..f621992 100644
--- a/test/core/Circle.js
+++ b/test/core/Circle.js
@@ -53,6 +53,10 @@
expect(circ1.contains(10, 16)).to.be.false;
expect(circ1.contains(11, 15)).to.be.false;
expect(circ1.contains(0, 0)).to.be.false;
+
+ const circ2 = new PIXI.Circle(10, 10, 0);
+
+ expect(circ2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Container.js b/test/core/Container.js
index d11be33..cefde54 100644
--- a/test/core/Container.js
+++ b/test/core/Container.js
@@ -2,30 +2,36 @@
function testAddChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.addChild(obj);
- });
- fn(function (container, obj)
- {
- container.addChildAt(obj);
- });
+ fn(function (container, obj)
+ {
+ container.addChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.addChildAt(obj);
+ });
+ };
}
function testRemoveChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.removeChild(obj);
- });
- fn(function (container, obj)
- {
- container.removeChildAt(container.children.indexOf(obj));
- });
- fn(function (container, obj)
- {
- container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
- });
+ fn(function (container, obj)
+ {
+ container.removeChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildAt(container.children.indexOf(obj));
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
+ });
+ };
}
describe('PIXI.Container', function ()
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/test/core/Circle.js b/test/core/Circle.js
index 183f98f..f621992 100644
--- a/test/core/Circle.js
+++ b/test/core/Circle.js
@@ -53,6 +53,10 @@
expect(circ1.contains(10, 16)).to.be.false;
expect(circ1.contains(11, 15)).to.be.false;
expect(circ1.contains(0, 0)).to.be.false;
+
+ const circ2 = new PIXI.Circle(10, 10, 0);
+
+ expect(circ2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Container.js b/test/core/Container.js
index d11be33..cefde54 100644
--- a/test/core/Container.js
+++ b/test/core/Container.js
@@ -2,30 +2,36 @@
function testAddChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.addChild(obj);
- });
- fn(function (container, obj)
- {
- container.addChildAt(obj);
- });
+ fn(function (container, obj)
+ {
+ container.addChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.addChildAt(obj);
+ });
+ };
}
function testRemoveChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.removeChild(obj);
- });
- fn(function (container, obj)
- {
- container.removeChildAt(container.children.indexOf(obj));
- });
- fn(function (container, obj)
- {
- container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
- });
+ fn(function (container, obj)
+ {
+ container.removeChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildAt(container.children.indexOf(obj));
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
+ });
+ };
}
describe('PIXI.Container', function ()
diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js
index f2e8234..3f47442 100644
--- a/test/core/Ellipse.js
+++ b/test/core/Ellipse.js
@@ -56,6 +56,10 @@
expect(ellipse1.contains(10, 16)).to.be.false;
expect(ellipse1.contains(11, 15)).to.be.false;
expect(ellipse1.contains(0, 0)).to.be.false;
+
+ const ellipse2 = new PIXI.Ellipse(10, 10, 0, 0);
+
+ expect(ellipse2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/test/core/Circle.js b/test/core/Circle.js
index 183f98f..f621992 100644
--- a/test/core/Circle.js
+++ b/test/core/Circle.js
@@ -53,6 +53,10 @@
expect(circ1.contains(10, 16)).to.be.false;
expect(circ1.contains(11, 15)).to.be.false;
expect(circ1.contains(0, 0)).to.be.false;
+
+ const circ2 = new PIXI.Circle(10, 10, 0);
+
+ expect(circ2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Container.js b/test/core/Container.js
index d11be33..cefde54 100644
--- a/test/core/Container.js
+++ b/test/core/Container.js
@@ -2,30 +2,36 @@
function testAddChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.addChild(obj);
- });
- fn(function (container, obj)
- {
- container.addChildAt(obj);
- });
+ fn(function (container, obj)
+ {
+ container.addChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.addChildAt(obj);
+ });
+ };
}
function testRemoveChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.removeChild(obj);
- });
- fn(function (container, obj)
- {
- container.removeChildAt(container.children.indexOf(obj));
- });
- fn(function (container, obj)
- {
- container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
- });
+ fn(function (container, obj)
+ {
+ container.removeChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildAt(container.children.indexOf(obj));
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
+ });
+ };
}
describe('PIXI.Container', function ()
diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js
index f2e8234..3f47442 100644
--- a/test/core/Ellipse.js
+++ b/test/core/Ellipse.js
@@ -56,6 +56,10 @@
expect(ellipse1.contains(10, 16)).to.be.false;
expect(ellipse1.contains(11, 15)).to.be.false;
expect(ellipse1.contains(0, 0)).to.be.false;
+
+ const ellipse2 = new PIXI.Ellipse(10, 10, 0, 0);
+
+ expect(ellipse2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Matrix.js b/test/core/Matrix.js
index 9d2694b..76bd57c 100644
--- a/test/core/Matrix.js
+++ b/test/core/Matrix.js
@@ -107,10 +107,60 @@
expect(m1.ty).to.equal(m2.ty);
});
+ it('should prepend matrix', function ()
+ {
+ const m1 = new PIXI.Matrix();
+ const m2 = new PIXI.Matrix();
+
+ m2.set(2, 3, 4, 5, 100, 200);
+ m1.prepend(m2);
+
+ expect(m1.a).to.equal(m2.a);
+ expect(m1.b).to.equal(m2.b);
+ expect(m1.c).to.equal(m2.c);
+ expect(m1.d).to.equal(m2.d);
+ expect(m1.tx).to.equal(m2.tx);
+ expect(m1.ty).to.equal(m2.ty);
+
+ const m3 = new PIXI.Matrix();
+ const m4 = new PIXI.Matrix();
+
+ m3.prepend(m4);
+
+ expect(m3.a).to.equal(m4.a);
+ expect(m3.b).to.equal(m4.b);
+ expect(m3.c).to.equal(m4.c);
+ expect(m3.d).to.equal(m4.d);
+ expect(m3.tx).to.equal(m4.tx);
+ expect(m3.ty).to.equal(m4.ty);
+ });
+
it('should get IDENTITY and TEMP_MATRIX', function ()
{
expect(PIXI.Matrix.IDENTITY instanceof PIXI.Matrix).to.be.true;
expect(PIXI.Matrix.TEMP_MATRIX instanceof PIXI.Matrix).to.be.true;
});
-});
+ it('should reset matrix to default when identity() is called', function ()
+ {
+ const matrix = new PIXI.Matrix();
+
+ matrix.set(2, 3, 4, 5, 100, 200);
+
+ expect(matrix.a).to.equal(2);
+ expect(matrix.b).to.equal(3);
+ expect(matrix.c).to.equal(4);
+ expect(matrix.d).to.equal(5);
+ expect(matrix.tx).to.equal(100);
+ expect(matrix.ty).to.equal(200);
+
+ matrix.identity();
+
+ expect(matrix.a).to.equal(1);
+ expect(matrix.b).to.equal(0);
+ expect(matrix.c).to.equal(0);
+ expect(matrix.d).to.equal(1);
+ expect(matrix.tx).to.equal(0);
+ expect(matrix.ty).to.equal(0);
+ });
+});
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/test/core/Circle.js b/test/core/Circle.js
index 183f98f..f621992 100644
--- a/test/core/Circle.js
+++ b/test/core/Circle.js
@@ -53,6 +53,10 @@
expect(circ1.contains(10, 16)).to.be.false;
expect(circ1.contains(11, 15)).to.be.false;
expect(circ1.contains(0, 0)).to.be.false;
+
+ const circ2 = new PIXI.Circle(10, 10, 0);
+
+ expect(circ2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Container.js b/test/core/Container.js
index d11be33..cefde54 100644
--- a/test/core/Container.js
+++ b/test/core/Container.js
@@ -2,30 +2,36 @@
function testAddChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.addChild(obj);
- });
- fn(function (container, obj)
- {
- container.addChildAt(obj);
- });
+ fn(function (container, obj)
+ {
+ container.addChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.addChildAt(obj);
+ });
+ };
}
function testRemoveChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.removeChild(obj);
- });
- fn(function (container, obj)
- {
- container.removeChildAt(container.children.indexOf(obj));
- });
- fn(function (container, obj)
- {
- container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
- });
+ fn(function (container, obj)
+ {
+ container.removeChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildAt(container.children.indexOf(obj));
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
+ });
+ };
}
describe('PIXI.Container', function ()
diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js
index f2e8234..3f47442 100644
--- a/test/core/Ellipse.js
+++ b/test/core/Ellipse.js
@@ -56,6 +56,10 @@
expect(ellipse1.contains(10, 16)).to.be.false;
expect(ellipse1.contains(11, 15)).to.be.false;
expect(ellipse1.contains(0, 0)).to.be.false;
+
+ const ellipse2 = new PIXI.Ellipse(10, 10, 0, 0);
+
+ expect(ellipse2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Matrix.js b/test/core/Matrix.js
index 9d2694b..76bd57c 100644
--- a/test/core/Matrix.js
+++ b/test/core/Matrix.js
@@ -107,10 +107,60 @@
expect(m1.ty).to.equal(m2.ty);
});
+ it('should prepend matrix', function ()
+ {
+ const m1 = new PIXI.Matrix();
+ const m2 = new PIXI.Matrix();
+
+ m2.set(2, 3, 4, 5, 100, 200);
+ m1.prepend(m2);
+
+ expect(m1.a).to.equal(m2.a);
+ expect(m1.b).to.equal(m2.b);
+ expect(m1.c).to.equal(m2.c);
+ expect(m1.d).to.equal(m2.d);
+ expect(m1.tx).to.equal(m2.tx);
+ expect(m1.ty).to.equal(m2.ty);
+
+ const m3 = new PIXI.Matrix();
+ const m4 = new PIXI.Matrix();
+
+ m3.prepend(m4);
+
+ expect(m3.a).to.equal(m4.a);
+ expect(m3.b).to.equal(m4.b);
+ expect(m3.c).to.equal(m4.c);
+ expect(m3.d).to.equal(m4.d);
+ expect(m3.tx).to.equal(m4.tx);
+ expect(m3.ty).to.equal(m4.ty);
+ });
+
it('should get IDENTITY and TEMP_MATRIX', function ()
{
expect(PIXI.Matrix.IDENTITY instanceof PIXI.Matrix).to.be.true;
expect(PIXI.Matrix.TEMP_MATRIX instanceof PIXI.Matrix).to.be.true;
});
-});
+ it('should reset matrix to default when identity() is called', function ()
+ {
+ const matrix = new PIXI.Matrix();
+
+ matrix.set(2, 3, 4, 5, 100, 200);
+
+ expect(matrix.a).to.equal(2);
+ expect(matrix.b).to.equal(3);
+ expect(matrix.c).to.equal(4);
+ expect(matrix.d).to.equal(5);
+ expect(matrix.tx).to.equal(100);
+ expect(matrix.ty).to.equal(200);
+
+ matrix.identity();
+
+ expect(matrix.a).to.equal(1);
+ expect(matrix.b).to.equal(0);
+ expect(matrix.c).to.equal(0);
+ expect(matrix.d).to.equal(1);
+ expect(matrix.tx).to.equal(0);
+ expect(matrix.ty).to.equal(0);
+ });
+});
diff --git a/test/core/Spritesheet.js b/test/core/Spritesheet.js
index 283adf5..7601a0c 100644
--- a/test/core/Spritesheet.js
+++ b/test/core/Spritesheet.js
@@ -18,6 +18,7 @@
expect(textures[id]).to.be.an.instanceof(PIXI.Texture);
expect(textures[id].width).to.equal(spritesheet.data.frames[id].frame.w / spritesheet.resolution);
expect(textures[id].height).to.equal(spritesheet.data.frames[id].frame.h / spritesheet.resolution);
+ expect(textures[id].textureCacheId).to.equal(id);
spritesheet.destroy(true);
expect(spritesheet.textures).to.be.null;
expect(spritesheet.baseTexture).to.be.null;
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/test/core/Circle.js b/test/core/Circle.js
index 183f98f..f621992 100644
--- a/test/core/Circle.js
+++ b/test/core/Circle.js
@@ -53,6 +53,10 @@
expect(circ1.contains(10, 16)).to.be.false;
expect(circ1.contains(11, 15)).to.be.false;
expect(circ1.contains(0, 0)).to.be.false;
+
+ const circ2 = new PIXI.Circle(10, 10, 0);
+
+ expect(circ2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Container.js b/test/core/Container.js
index d11be33..cefde54 100644
--- a/test/core/Container.js
+++ b/test/core/Container.js
@@ -2,30 +2,36 @@
function testAddChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.addChild(obj);
- });
- fn(function (container, obj)
- {
- container.addChildAt(obj);
- });
+ fn(function (container, obj)
+ {
+ container.addChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.addChildAt(obj);
+ });
+ };
}
function testRemoveChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.removeChild(obj);
- });
- fn(function (container, obj)
- {
- container.removeChildAt(container.children.indexOf(obj));
- });
- fn(function (container, obj)
- {
- container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
- });
+ fn(function (container, obj)
+ {
+ container.removeChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildAt(container.children.indexOf(obj));
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
+ });
+ };
}
describe('PIXI.Container', function ()
diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js
index f2e8234..3f47442 100644
--- a/test/core/Ellipse.js
+++ b/test/core/Ellipse.js
@@ -56,6 +56,10 @@
expect(ellipse1.contains(10, 16)).to.be.false;
expect(ellipse1.contains(11, 15)).to.be.false;
expect(ellipse1.contains(0, 0)).to.be.false;
+
+ const ellipse2 = new PIXI.Ellipse(10, 10, 0, 0);
+
+ expect(ellipse2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Matrix.js b/test/core/Matrix.js
index 9d2694b..76bd57c 100644
--- a/test/core/Matrix.js
+++ b/test/core/Matrix.js
@@ -107,10 +107,60 @@
expect(m1.ty).to.equal(m2.ty);
});
+ it('should prepend matrix', function ()
+ {
+ const m1 = new PIXI.Matrix();
+ const m2 = new PIXI.Matrix();
+
+ m2.set(2, 3, 4, 5, 100, 200);
+ m1.prepend(m2);
+
+ expect(m1.a).to.equal(m2.a);
+ expect(m1.b).to.equal(m2.b);
+ expect(m1.c).to.equal(m2.c);
+ expect(m1.d).to.equal(m2.d);
+ expect(m1.tx).to.equal(m2.tx);
+ expect(m1.ty).to.equal(m2.ty);
+
+ const m3 = new PIXI.Matrix();
+ const m4 = new PIXI.Matrix();
+
+ m3.prepend(m4);
+
+ expect(m3.a).to.equal(m4.a);
+ expect(m3.b).to.equal(m4.b);
+ expect(m3.c).to.equal(m4.c);
+ expect(m3.d).to.equal(m4.d);
+ expect(m3.tx).to.equal(m4.tx);
+ expect(m3.ty).to.equal(m4.ty);
+ });
+
it('should get IDENTITY and TEMP_MATRIX', function ()
{
expect(PIXI.Matrix.IDENTITY instanceof PIXI.Matrix).to.be.true;
expect(PIXI.Matrix.TEMP_MATRIX instanceof PIXI.Matrix).to.be.true;
});
-});
+ it('should reset matrix to default when identity() is called', function ()
+ {
+ const matrix = new PIXI.Matrix();
+
+ matrix.set(2, 3, 4, 5, 100, 200);
+
+ expect(matrix.a).to.equal(2);
+ expect(matrix.b).to.equal(3);
+ expect(matrix.c).to.equal(4);
+ expect(matrix.d).to.equal(5);
+ expect(matrix.tx).to.equal(100);
+ expect(matrix.ty).to.equal(200);
+
+ matrix.identity();
+
+ expect(matrix.a).to.equal(1);
+ expect(matrix.b).to.equal(0);
+ expect(matrix.c).to.equal(0);
+ expect(matrix.d).to.equal(1);
+ expect(matrix.tx).to.equal(0);
+ expect(matrix.ty).to.equal(0);
+ });
+});
diff --git a/test/core/Spritesheet.js b/test/core/Spritesheet.js
index 283adf5..7601a0c 100644
--- a/test/core/Spritesheet.js
+++ b/test/core/Spritesheet.js
@@ -18,6 +18,7 @@
expect(textures[id]).to.be.an.instanceof(PIXI.Texture);
expect(textures[id].width).to.equal(spritesheet.data.frames[id].frame.w / spritesheet.resolution);
expect(textures[id].height).to.equal(spritesheet.data.frames[id].frame.h / spritesheet.resolution);
+ expect(textures[id].textureCacheId).to.equal(id);
spritesheet.destroy(true);
expect(spritesheet.textures).to.be.null;
expect(spritesheet.baseTexture).to.be.null;
diff --git a/test/core/Texture.js b/test/core/Texture.js
index 8c4ef98..241ec3e 100644
--- a/test/core/Texture.js
+++ b/test/core/Texture.js
@@ -16,4 +16,20 @@
expect(PIXI.utils.TextureCache[URL]).to.equal(texture);
expect(PIXI.utils.BaseTextureCache[URL]).to.equal(texture.baseTexture);
});
+
+ it('should remove Texture from cache on destroy', function ()
+ {
+ const NAME = 'foo';
+ const NAME2 = 'bar';
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+
+ PIXI.Texture.addTextureToCache(texture, NAME);
+ PIXI.Texture.addTextureToCache(texture, NAME2);
+ expect(texture.textureCacheId).to.equal(NAME);
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(texture);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(undefined);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(undefined);
+ });
});
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/test/core/Circle.js b/test/core/Circle.js
index 183f98f..f621992 100644
--- a/test/core/Circle.js
+++ b/test/core/Circle.js
@@ -53,6 +53,10 @@
expect(circ1.contains(10, 16)).to.be.false;
expect(circ1.contains(11, 15)).to.be.false;
expect(circ1.contains(0, 0)).to.be.false;
+
+ const circ2 = new PIXI.Circle(10, 10, 0);
+
+ expect(circ2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Container.js b/test/core/Container.js
index d11be33..cefde54 100644
--- a/test/core/Container.js
+++ b/test/core/Container.js
@@ -2,30 +2,36 @@
function testAddChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.addChild(obj);
- });
- fn(function (container, obj)
- {
- container.addChildAt(obj);
- });
+ fn(function (container, obj)
+ {
+ container.addChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.addChildAt(obj);
+ });
+ };
}
function testRemoveChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.removeChild(obj);
- });
- fn(function (container, obj)
- {
- container.removeChildAt(container.children.indexOf(obj));
- });
- fn(function (container, obj)
- {
- container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
- });
+ fn(function (container, obj)
+ {
+ container.removeChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildAt(container.children.indexOf(obj));
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
+ });
+ };
}
describe('PIXI.Container', function ()
diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js
index f2e8234..3f47442 100644
--- a/test/core/Ellipse.js
+++ b/test/core/Ellipse.js
@@ -56,6 +56,10 @@
expect(ellipse1.contains(10, 16)).to.be.false;
expect(ellipse1.contains(11, 15)).to.be.false;
expect(ellipse1.contains(0, 0)).to.be.false;
+
+ const ellipse2 = new PIXI.Ellipse(10, 10, 0, 0);
+
+ expect(ellipse2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Matrix.js b/test/core/Matrix.js
index 9d2694b..76bd57c 100644
--- a/test/core/Matrix.js
+++ b/test/core/Matrix.js
@@ -107,10 +107,60 @@
expect(m1.ty).to.equal(m2.ty);
});
+ it('should prepend matrix', function ()
+ {
+ const m1 = new PIXI.Matrix();
+ const m2 = new PIXI.Matrix();
+
+ m2.set(2, 3, 4, 5, 100, 200);
+ m1.prepend(m2);
+
+ expect(m1.a).to.equal(m2.a);
+ expect(m1.b).to.equal(m2.b);
+ expect(m1.c).to.equal(m2.c);
+ expect(m1.d).to.equal(m2.d);
+ expect(m1.tx).to.equal(m2.tx);
+ expect(m1.ty).to.equal(m2.ty);
+
+ const m3 = new PIXI.Matrix();
+ const m4 = new PIXI.Matrix();
+
+ m3.prepend(m4);
+
+ expect(m3.a).to.equal(m4.a);
+ expect(m3.b).to.equal(m4.b);
+ expect(m3.c).to.equal(m4.c);
+ expect(m3.d).to.equal(m4.d);
+ expect(m3.tx).to.equal(m4.tx);
+ expect(m3.ty).to.equal(m4.ty);
+ });
+
it('should get IDENTITY and TEMP_MATRIX', function ()
{
expect(PIXI.Matrix.IDENTITY instanceof PIXI.Matrix).to.be.true;
expect(PIXI.Matrix.TEMP_MATRIX instanceof PIXI.Matrix).to.be.true;
});
-});
+ it('should reset matrix to default when identity() is called', function ()
+ {
+ const matrix = new PIXI.Matrix();
+
+ matrix.set(2, 3, 4, 5, 100, 200);
+
+ expect(matrix.a).to.equal(2);
+ expect(matrix.b).to.equal(3);
+ expect(matrix.c).to.equal(4);
+ expect(matrix.d).to.equal(5);
+ expect(matrix.tx).to.equal(100);
+ expect(matrix.ty).to.equal(200);
+
+ matrix.identity();
+
+ expect(matrix.a).to.equal(1);
+ expect(matrix.b).to.equal(0);
+ expect(matrix.c).to.equal(0);
+ expect(matrix.d).to.equal(1);
+ expect(matrix.tx).to.equal(0);
+ expect(matrix.ty).to.equal(0);
+ });
+});
diff --git a/test/core/Spritesheet.js b/test/core/Spritesheet.js
index 283adf5..7601a0c 100644
--- a/test/core/Spritesheet.js
+++ b/test/core/Spritesheet.js
@@ -18,6 +18,7 @@
expect(textures[id]).to.be.an.instanceof(PIXI.Texture);
expect(textures[id].width).to.equal(spritesheet.data.frames[id].frame.w / spritesheet.resolution);
expect(textures[id].height).to.equal(spritesheet.data.frames[id].frame.h / spritesheet.resolution);
+ expect(textures[id].textureCacheId).to.equal(id);
spritesheet.destroy(true);
expect(spritesheet.textures).to.be.null;
expect(spritesheet.baseTexture).to.be.null;
diff --git a/test/core/Texture.js b/test/core/Texture.js
index 8c4ef98..241ec3e 100644
--- a/test/core/Texture.js
+++ b/test/core/Texture.js
@@ -16,4 +16,20 @@
expect(PIXI.utils.TextureCache[URL]).to.equal(texture);
expect(PIXI.utils.BaseTextureCache[URL]).to.equal(texture.baseTexture);
});
+
+ it('should remove Texture from cache on destroy', function ()
+ {
+ const NAME = 'foo';
+ const NAME2 = 'bar';
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+
+ PIXI.Texture.addTextureToCache(texture, NAME);
+ PIXI.Texture.addTextureToCache(texture, NAME2);
+ expect(texture.textureCacheId).to.equal(NAME);
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(texture);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(undefined);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(undefined);
+ });
});
diff --git a/test/core/Ticker.js b/test/core/Ticker.js
new file mode 100644
index 0000000..188770f
--- /dev/null
+++ b/test/core/Ticker.js
@@ -0,0 +1,322 @@
+'use strict';
+
+const Ticker = PIXI.ticker.Ticker;
+const shared = PIXI.ticker.shared;
+
+describe('PIXI.ticker.Ticker', function ()
+{
+ before(function ()
+ {
+ this.length = (ticker) =>
+ {
+ ticker = ticker || shared;
+
+ if (!ticker._head || !ticker._head.next)
+ {
+ return 0;
+ }
+
+ let listener = ticker._head.next;
+ let i = 0;
+
+ while (listener)
+ {
+ listener = listener.next;
+ i++;
+ }
+
+ return i;
+ };
+ });
+
+ it('should be available', function ()
+ {
+ expect(Ticker).to.be.a.function;
+ expect(shared).to.be.an.instanceof(Ticker);
+ });
+
+ it('should create a new ticker and destroy it', function ()
+ {
+ const ticker = new Ticker();
+
+ ticker.start();
+
+ const listener = sinon.spy();
+
+ expect(this.length(ticker)).to.equal(0);
+
+ ticker.add(listener);
+
+ expect(this.length(ticker)).to.equal(1);
+
+ ticker.destroy();
+
+ expect(ticker._head).to.be.null;
+ expect(ticker.started).to.be.false;
+ expect(this.length(ticker)).to.equal(0);
+ });
+
+ it('should protect destroying shared ticker', function ()
+ {
+ shared.destroy();
+ expect(shared._head).to.not.be.null;
+ expect(shared.started).to.be.true;
+ });
+
+ it('should add and remove listener', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener);
+
+ expect(this.length()).to.equal(length + 1);
+
+ shared.remove(listener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should update a listener', function ()
+ {
+ const listener = sinon.spy();
+
+ shared.add(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ });
+
+ it('should update a listener twice and remove once', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener).add(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length + 2);
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should respect priority order', function ()
+ {
+ const length = this.length();
+ const listener1 = sinon.spy();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.LOW)
+ .add(listener4, null, PIXI.UPDATE_PRIORITY.INTERACTION)
+ .add(listener3, null, PIXI.UPDATE_PRIORITY.HIGH)
+ .add(listener2, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 4);
+
+ sinon.assert.callOrder(listener4, listener3, listener2, listener1);
+
+ shared.remove(listener1)
+ .remove(listener2)
+ .remove(listener3)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should auto-remove once listeners', function ()
+ {
+ const length = this.length();
+ const listener = sinon.spy();
+
+ shared.addOnce(listener);
+
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should call inserted item with a lower priority', function ()
+ {
+ const length = this.length();
+ const lowListener = sinon.spy();
+ const highListener = sinon.spy();
+ const mainListener = sinon.spy(() =>
+ {
+ shared.add(highListener, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(lowListener, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(mainListener, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 3);
+
+ expect(mainListener.calledOnce).to.be.true;
+ expect(lowListener.calledOnce).to.be.true;
+ expect(highListener.calledOnce).to.be.false;
+
+ shared.remove(mainListener)
+ .remove(highListener)
+ .remove(lowListener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove emit low-priority item during emit', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself on emit after adding new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.remove(listener1);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself before, still calling new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener1);
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove items before and after current priority', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(listener3, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.add(listener4, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener2)
+ .remove(listener3);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 2);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.update();
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledTwice).to.be.true;
+ expect(listener1.calledTwice).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should destroy on listener', function (done)
+ {
+ const ticker = new Ticker();
+ const listener2 = sinon.spy();
+ const listener = sinon.spy(() =>
+ {
+ ticker.destroy();
+ setTimeout(() =>
+ {
+ expect(listener2.called).to.be.false;
+ expect(listener.calledOnce).to.be.true;
+ done();
+ }, 0);
+ });
+
+ ticker.add(listener);
+ ticker.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ ticker.start();
+ });
+});
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/test/core/Circle.js b/test/core/Circle.js
index 183f98f..f621992 100644
--- a/test/core/Circle.js
+++ b/test/core/Circle.js
@@ -53,6 +53,10 @@
expect(circ1.contains(10, 16)).to.be.false;
expect(circ1.contains(11, 15)).to.be.false;
expect(circ1.contains(0, 0)).to.be.false;
+
+ const circ2 = new PIXI.Circle(10, 10, 0);
+
+ expect(circ2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Container.js b/test/core/Container.js
index d11be33..cefde54 100644
--- a/test/core/Container.js
+++ b/test/core/Container.js
@@ -2,30 +2,36 @@
function testAddChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.addChild(obj);
- });
- fn(function (container, obj)
- {
- container.addChildAt(obj);
- });
+ fn(function (container, obj)
+ {
+ container.addChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.addChildAt(obj);
+ });
+ };
}
function testRemoveChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.removeChild(obj);
- });
- fn(function (container, obj)
- {
- container.removeChildAt(container.children.indexOf(obj));
- });
- fn(function (container, obj)
- {
- container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
- });
+ fn(function (container, obj)
+ {
+ container.removeChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildAt(container.children.indexOf(obj));
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
+ });
+ };
}
describe('PIXI.Container', function ()
diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js
index f2e8234..3f47442 100644
--- a/test/core/Ellipse.js
+++ b/test/core/Ellipse.js
@@ -56,6 +56,10 @@
expect(ellipse1.contains(10, 16)).to.be.false;
expect(ellipse1.contains(11, 15)).to.be.false;
expect(ellipse1.contains(0, 0)).to.be.false;
+
+ const ellipse2 = new PIXI.Ellipse(10, 10, 0, 0);
+
+ expect(ellipse2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Matrix.js b/test/core/Matrix.js
index 9d2694b..76bd57c 100644
--- a/test/core/Matrix.js
+++ b/test/core/Matrix.js
@@ -107,10 +107,60 @@
expect(m1.ty).to.equal(m2.ty);
});
+ it('should prepend matrix', function ()
+ {
+ const m1 = new PIXI.Matrix();
+ const m2 = new PIXI.Matrix();
+
+ m2.set(2, 3, 4, 5, 100, 200);
+ m1.prepend(m2);
+
+ expect(m1.a).to.equal(m2.a);
+ expect(m1.b).to.equal(m2.b);
+ expect(m1.c).to.equal(m2.c);
+ expect(m1.d).to.equal(m2.d);
+ expect(m1.tx).to.equal(m2.tx);
+ expect(m1.ty).to.equal(m2.ty);
+
+ const m3 = new PIXI.Matrix();
+ const m4 = new PIXI.Matrix();
+
+ m3.prepend(m4);
+
+ expect(m3.a).to.equal(m4.a);
+ expect(m3.b).to.equal(m4.b);
+ expect(m3.c).to.equal(m4.c);
+ expect(m3.d).to.equal(m4.d);
+ expect(m3.tx).to.equal(m4.tx);
+ expect(m3.ty).to.equal(m4.ty);
+ });
+
it('should get IDENTITY and TEMP_MATRIX', function ()
{
expect(PIXI.Matrix.IDENTITY instanceof PIXI.Matrix).to.be.true;
expect(PIXI.Matrix.TEMP_MATRIX instanceof PIXI.Matrix).to.be.true;
});
-});
+ it('should reset matrix to default when identity() is called', function ()
+ {
+ const matrix = new PIXI.Matrix();
+
+ matrix.set(2, 3, 4, 5, 100, 200);
+
+ expect(matrix.a).to.equal(2);
+ expect(matrix.b).to.equal(3);
+ expect(matrix.c).to.equal(4);
+ expect(matrix.d).to.equal(5);
+ expect(matrix.tx).to.equal(100);
+ expect(matrix.ty).to.equal(200);
+
+ matrix.identity();
+
+ expect(matrix.a).to.equal(1);
+ expect(matrix.b).to.equal(0);
+ expect(matrix.c).to.equal(0);
+ expect(matrix.d).to.equal(1);
+ expect(matrix.tx).to.equal(0);
+ expect(matrix.ty).to.equal(0);
+ });
+});
diff --git a/test/core/Spritesheet.js b/test/core/Spritesheet.js
index 283adf5..7601a0c 100644
--- a/test/core/Spritesheet.js
+++ b/test/core/Spritesheet.js
@@ -18,6 +18,7 @@
expect(textures[id]).to.be.an.instanceof(PIXI.Texture);
expect(textures[id].width).to.equal(spritesheet.data.frames[id].frame.w / spritesheet.resolution);
expect(textures[id].height).to.equal(spritesheet.data.frames[id].frame.h / spritesheet.resolution);
+ expect(textures[id].textureCacheId).to.equal(id);
spritesheet.destroy(true);
expect(spritesheet.textures).to.be.null;
expect(spritesheet.baseTexture).to.be.null;
diff --git a/test/core/Texture.js b/test/core/Texture.js
index 8c4ef98..241ec3e 100644
--- a/test/core/Texture.js
+++ b/test/core/Texture.js
@@ -16,4 +16,20 @@
expect(PIXI.utils.TextureCache[URL]).to.equal(texture);
expect(PIXI.utils.BaseTextureCache[URL]).to.equal(texture.baseTexture);
});
+
+ it('should remove Texture from cache on destroy', function ()
+ {
+ const NAME = 'foo';
+ const NAME2 = 'bar';
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+
+ PIXI.Texture.addTextureToCache(texture, NAME);
+ PIXI.Texture.addTextureToCache(texture, NAME2);
+ expect(texture.textureCacheId).to.equal(NAME);
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(texture);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(undefined);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(undefined);
+ });
});
diff --git a/test/core/Ticker.js b/test/core/Ticker.js
new file mode 100644
index 0000000..188770f
--- /dev/null
+++ b/test/core/Ticker.js
@@ -0,0 +1,322 @@
+'use strict';
+
+const Ticker = PIXI.ticker.Ticker;
+const shared = PIXI.ticker.shared;
+
+describe('PIXI.ticker.Ticker', function ()
+{
+ before(function ()
+ {
+ this.length = (ticker) =>
+ {
+ ticker = ticker || shared;
+
+ if (!ticker._head || !ticker._head.next)
+ {
+ return 0;
+ }
+
+ let listener = ticker._head.next;
+ let i = 0;
+
+ while (listener)
+ {
+ listener = listener.next;
+ i++;
+ }
+
+ return i;
+ };
+ });
+
+ it('should be available', function ()
+ {
+ expect(Ticker).to.be.a.function;
+ expect(shared).to.be.an.instanceof(Ticker);
+ });
+
+ it('should create a new ticker and destroy it', function ()
+ {
+ const ticker = new Ticker();
+
+ ticker.start();
+
+ const listener = sinon.spy();
+
+ expect(this.length(ticker)).to.equal(0);
+
+ ticker.add(listener);
+
+ expect(this.length(ticker)).to.equal(1);
+
+ ticker.destroy();
+
+ expect(ticker._head).to.be.null;
+ expect(ticker.started).to.be.false;
+ expect(this.length(ticker)).to.equal(0);
+ });
+
+ it('should protect destroying shared ticker', function ()
+ {
+ shared.destroy();
+ expect(shared._head).to.not.be.null;
+ expect(shared.started).to.be.true;
+ });
+
+ it('should add and remove listener', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener);
+
+ expect(this.length()).to.equal(length + 1);
+
+ shared.remove(listener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should update a listener', function ()
+ {
+ const listener = sinon.spy();
+
+ shared.add(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ });
+
+ it('should update a listener twice and remove once', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener).add(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length + 2);
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should respect priority order', function ()
+ {
+ const length = this.length();
+ const listener1 = sinon.spy();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.LOW)
+ .add(listener4, null, PIXI.UPDATE_PRIORITY.INTERACTION)
+ .add(listener3, null, PIXI.UPDATE_PRIORITY.HIGH)
+ .add(listener2, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 4);
+
+ sinon.assert.callOrder(listener4, listener3, listener2, listener1);
+
+ shared.remove(listener1)
+ .remove(listener2)
+ .remove(listener3)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should auto-remove once listeners', function ()
+ {
+ const length = this.length();
+ const listener = sinon.spy();
+
+ shared.addOnce(listener);
+
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should call inserted item with a lower priority', function ()
+ {
+ const length = this.length();
+ const lowListener = sinon.spy();
+ const highListener = sinon.spy();
+ const mainListener = sinon.spy(() =>
+ {
+ shared.add(highListener, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(lowListener, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(mainListener, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 3);
+
+ expect(mainListener.calledOnce).to.be.true;
+ expect(lowListener.calledOnce).to.be.true;
+ expect(highListener.calledOnce).to.be.false;
+
+ shared.remove(mainListener)
+ .remove(highListener)
+ .remove(lowListener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove emit low-priority item during emit', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself on emit after adding new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.remove(listener1);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself before, still calling new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener1);
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove items before and after current priority', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(listener3, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.add(listener4, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener2)
+ .remove(listener3);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 2);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.update();
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledTwice).to.be.true;
+ expect(listener1.calledTwice).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should destroy on listener', function (done)
+ {
+ const ticker = new Ticker();
+ const listener2 = sinon.spy();
+ const listener = sinon.spy(() =>
+ {
+ ticker.destroy();
+ setTimeout(() =>
+ {
+ expect(listener2.called).to.be.false;
+ expect(listener.calledOnce).to.be.true;
+ done();
+ }, 0);
+ });
+
+ ticker.add(listener);
+ ticker.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ ticker.start();
+ });
+});
diff --git a/test/core/TilingSprite.js b/test/core/TilingSprite.js
index 2e449a7..7694792 100644
--- a/test/core/TilingSprite.js
+++ b/test/core/TilingSprite.js
@@ -24,4 +24,25 @@
expect(bounds.height).to.equal(600);
});
});
+
+ it('checks if tilingSprite contains a point', function ()
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+ const tilingSprite = new PIXI.extras.TilingSprite(texture, 200, 300);
+
+ expect(tilingSprite.containsPoint(new PIXI.Point(1, 1))).to.equal(true);
+ expect(tilingSprite.containsPoint(new PIXI.Point(300, 400))).to.equal(false);
+ });
+
+ it('gets and sets height and width correctly', function ()
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+ const tilingSprite = new PIXI.extras.TilingSprite(texture, 200, 300);
+
+ tilingSprite.width = 400;
+ tilingSprite.height = 600;
+
+ expect(tilingSprite.width).to.equal(400);
+ expect(tilingSprite.height).to.equal(600);
+ });
});
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/test/core/Circle.js b/test/core/Circle.js
index 183f98f..f621992 100644
--- a/test/core/Circle.js
+++ b/test/core/Circle.js
@@ -53,6 +53,10 @@
expect(circ1.contains(10, 16)).to.be.false;
expect(circ1.contains(11, 15)).to.be.false;
expect(circ1.contains(0, 0)).to.be.false;
+
+ const circ2 = new PIXI.Circle(10, 10, 0);
+
+ expect(circ2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Container.js b/test/core/Container.js
index d11be33..cefde54 100644
--- a/test/core/Container.js
+++ b/test/core/Container.js
@@ -2,30 +2,36 @@
function testAddChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.addChild(obj);
- });
- fn(function (container, obj)
- {
- container.addChildAt(obj);
- });
+ fn(function (container, obj)
+ {
+ container.addChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.addChildAt(obj);
+ });
+ };
}
function testRemoveChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.removeChild(obj);
- });
- fn(function (container, obj)
- {
- container.removeChildAt(container.children.indexOf(obj));
- });
- fn(function (container, obj)
- {
- container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
- });
+ fn(function (container, obj)
+ {
+ container.removeChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildAt(container.children.indexOf(obj));
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
+ });
+ };
}
describe('PIXI.Container', function ()
diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js
index f2e8234..3f47442 100644
--- a/test/core/Ellipse.js
+++ b/test/core/Ellipse.js
@@ -56,6 +56,10 @@
expect(ellipse1.contains(10, 16)).to.be.false;
expect(ellipse1.contains(11, 15)).to.be.false;
expect(ellipse1.contains(0, 0)).to.be.false;
+
+ const ellipse2 = new PIXI.Ellipse(10, 10, 0, 0);
+
+ expect(ellipse2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Matrix.js b/test/core/Matrix.js
index 9d2694b..76bd57c 100644
--- a/test/core/Matrix.js
+++ b/test/core/Matrix.js
@@ -107,10 +107,60 @@
expect(m1.ty).to.equal(m2.ty);
});
+ it('should prepend matrix', function ()
+ {
+ const m1 = new PIXI.Matrix();
+ const m2 = new PIXI.Matrix();
+
+ m2.set(2, 3, 4, 5, 100, 200);
+ m1.prepend(m2);
+
+ expect(m1.a).to.equal(m2.a);
+ expect(m1.b).to.equal(m2.b);
+ expect(m1.c).to.equal(m2.c);
+ expect(m1.d).to.equal(m2.d);
+ expect(m1.tx).to.equal(m2.tx);
+ expect(m1.ty).to.equal(m2.ty);
+
+ const m3 = new PIXI.Matrix();
+ const m4 = new PIXI.Matrix();
+
+ m3.prepend(m4);
+
+ expect(m3.a).to.equal(m4.a);
+ expect(m3.b).to.equal(m4.b);
+ expect(m3.c).to.equal(m4.c);
+ expect(m3.d).to.equal(m4.d);
+ expect(m3.tx).to.equal(m4.tx);
+ expect(m3.ty).to.equal(m4.ty);
+ });
+
it('should get IDENTITY and TEMP_MATRIX', function ()
{
expect(PIXI.Matrix.IDENTITY instanceof PIXI.Matrix).to.be.true;
expect(PIXI.Matrix.TEMP_MATRIX instanceof PIXI.Matrix).to.be.true;
});
-});
+ it('should reset matrix to default when identity() is called', function ()
+ {
+ const matrix = new PIXI.Matrix();
+
+ matrix.set(2, 3, 4, 5, 100, 200);
+
+ expect(matrix.a).to.equal(2);
+ expect(matrix.b).to.equal(3);
+ expect(matrix.c).to.equal(4);
+ expect(matrix.d).to.equal(5);
+ expect(matrix.tx).to.equal(100);
+ expect(matrix.ty).to.equal(200);
+
+ matrix.identity();
+
+ expect(matrix.a).to.equal(1);
+ expect(matrix.b).to.equal(0);
+ expect(matrix.c).to.equal(0);
+ expect(matrix.d).to.equal(1);
+ expect(matrix.tx).to.equal(0);
+ expect(matrix.ty).to.equal(0);
+ });
+});
diff --git a/test/core/Spritesheet.js b/test/core/Spritesheet.js
index 283adf5..7601a0c 100644
--- a/test/core/Spritesheet.js
+++ b/test/core/Spritesheet.js
@@ -18,6 +18,7 @@
expect(textures[id]).to.be.an.instanceof(PIXI.Texture);
expect(textures[id].width).to.equal(spritesheet.data.frames[id].frame.w / spritesheet.resolution);
expect(textures[id].height).to.equal(spritesheet.data.frames[id].frame.h / spritesheet.resolution);
+ expect(textures[id].textureCacheId).to.equal(id);
spritesheet.destroy(true);
expect(spritesheet.textures).to.be.null;
expect(spritesheet.baseTexture).to.be.null;
diff --git a/test/core/Texture.js b/test/core/Texture.js
index 8c4ef98..241ec3e 100644
--- a/test/core/Texture.js
+++ b/test/core/Texture.js
@@ -16,4 +16,20 @@
expect(PIXI.utils.TextureCache[URL]).to.equal(texture);
expect(PIXI.utils.BaseTextureCache[URL]).to.equal(texture.baseTexture);
});
+
+ it('should remove Texture from cache on destroy', function ()
+ {
+ const NAME = 'foo';
+ const NAME2 = 'bar';
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+
+ PIXI.Texture.addTextureToCache(texture, NAME);
+ PIXI.Texture.addTextureToCache(texture, NAME2);
+ expect(texture.textureCacheId).to.equal(NAME);
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(texture);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(undefined);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(undefined);
+ });
});
diff --git a/test/core/Ticker.js b/test/core/Ticker.js
new file mode 100644
index 0000000..188770f
--- /dev/null
+++ b/test/core/Ticker.js
@@ -0,0 +1,322 @@
+'use strict';
+
+const Ticker = PIXI.ticker.Ticker;
+const shared = PIXI.ticker.shared;
+
+describe('PIXI.ticker.Ticker', function ()
+{
+ before(function ()
+ {
+ this.length = (ticker) =>
+ {
+ ticker = ticker || shared;
+
+ if (!ticker._head || !ticker._head.next)
+ {
+ return 0;
+ }
+
+ let listener = ticker._head.next;
+ let i = 0;
+
+ while (listener)
+ {
+ listener = listener.next;
+ i++;
+ }
+
+ return i;
+ };
+ });
+
+ it('should be available', function ()
+ {
+ expect(Ticker).to.be.a.function;
+ expect(shared).to.be.an.instanceof(Ticker);
+ });
+
+ it('should create a new ticker and destroy it', function ()
+ {
+ const ticker = new Ticker();
+
+ ticker.start();
+
+ const listener = sinon.spy();
+
+ expect(this.length(ticker)).to.equal(0);
+
+ ticker.add(listener);
+
+ expect(this.length(ticker)).to.equal(1);
+
+ ticker.destroy();
+
+ expect(ticker._head).to.be.null;
+ expect(ticker.started).to.be.false;
+ expect(this.length(ticker)).to.equal(0);
+ });
+
+ it('should protect destroying shared ticker', function ()
+ {
+ shared.destroy();
+ expect(shared._head).to.not.be.null;
+ expect(shared.started).to.be.true;
+ });
+
+ it('should add and remove listener', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener);
+
+ expect(this.length()).to.equal(length + 1);
+
+ shared.remove(listener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should update a listener', function ()
+ {
+ const listener = sinon.spy();
+
+ shared.add(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ });
+
+ it('should update a listener twice and remove once', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener).add(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length + 2);
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should respect priority order', function ()
+ {
+ const length = this.length();
+ const listener1 = sinon.spy();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.LOW)
+ .add(listener4, null, PIXI.UPDATE_PRIORITY.INTERACTION)
+ .add(listener3, null, PIXI.UPDATE_PRIORITY.HIGH)
+ .add(listener2, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 4);
+
+ sinon.assert.callOrder(listener4, listener3, listener2, listener1);
+
+ shared.remove(listener1)
+ .remove(listener2)
+ .remove(listener3)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should auto-remove once listeners', function ()
+ {
+ const length = this.length();
+ const listener = sinon.spy();
+
+ shared.addOnce(listener);
+
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should call inserted item with a lower priority', function ()
+ {
+ const length = this.length();
+ const lowListener = sinon.spy();
+ const highListener = sinon.spy();
+ const mainListener = sinon.spy(() =>
+ {
+ shared.add(highListener, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(lowListener, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(mainListener, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 3);
+
+ expect(mainListener.calledOnce).to.be.true;
+ expect(lowListener.calledOnce).to.be.true;
+ expect(highListener.calledOnce).to.be.false;
+
+ shared.remove(mainListener)
+ .remove(highListener)
+ .remove(lowListener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove emit low-priority item during emit', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself on emit after adding new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.remove(listener1);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself before, still calling new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener1);
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove items before and after current priority', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(listener3, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.add(listener4, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener2)
+ .remove(listener3);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 2);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.update();
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledTwice).to.be.true;
+ expect(listener1.calledTwice).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should destroy on listener', function (done)
+ {
+ const ticker = new Ticker();
+ const listener2 = sinon.spy();
+ const listener = sinon.spy(() =>
+ {
+ ticker.destroy();
+ setTimeout(() =>
+ {
+ expect(listener2.called).to.be.false;
+ expect(listener.calledOnce).to.be.true;
+ done();
+ }, 0);
+ });
+
+ ticker.add(listener);
+ ticker.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ ticker.start();
+ });
+});
diff --git a/test/core/TilingSprite.js b/test/core/TilingSprite.js
index 2e449a7..7694792 100644
--- a/test/core/TilingSprite.js
+++ b/test/core/TilingSprite.js
@@ -24,4 +24,25 @@
expect(bounds.height).to.equal(600);
});
});
+
+ it('checks if tilingSprite contains a point', function ()
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+ const tilingSprite = new PIXI.extras.TilingSprite(texture, 200, 300);
+
+ expect(tilingSprite.containsPoint(new PIXI.Point(1, 1))).to.equal(true);
+ expect(tilingSprite.containsPoint(new PIXI.Point(300, 400))).to.equal(false);
+ });
+
+ it('gets and sets height and width correctly', function ()
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+ const tilingSprite = new PIXI.extras.TilingSprite(texture, 200, 300);
+
+ tilingSprite.width = 400;
+ tilingSprite.height = 600;
+
+ expect(tilingSprite.width).to.equal(400);
+ expect(tilingSprite.height).to.equal(600);
+ });
});
diff --git a/test/core/index.js b/test/core/index.js
index 8530131..58dc30e 100755
--- a/test/core/index.js
+++ b/test/core/index.js
@@ -17,6 +17,7 @@
require('./util');
require('./Plane');
require('./Point');
+require('./Polygon');
require('./ObservablePoint');
require('./Matrix');
require('./Rectangle');
@@ -27,4 +28,5 @@
require('./WebGLRenderer');
require('./Ellipse');
require('./Texture');
+require('./Ticker');
require('./filters');
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/test/core/Circle.js b/test/core/Circle.js
index 183f98f..f621992 100644
--- a/test/core/Circle.js
+++ b/test/core/Circle.js
@@ -53,6 +53,10 @@
expect(circ1.contains(10, 16)).to.be.false;
expect(circ1.contains(11, 15)).to.be.false;
expect(circ1.contains(0, 0)).to.be.false;
+
+ const circ2 = new PIXI.Circle(10, 10, 0);
+
+ expect(circ2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Container.js b/test/core/Container.js
index d11be33..cefde54 100644
--- a/test/core/Container.js
+++ b/test/core/Container.js
@@ -2,30 +2,36 @@
function testAddChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.addChild(obj);
- });
- fn(function (container, obj)
- {
- container.addChildAt(obj);
- });
+ fn(function (container, obj)
+ {
+ container.addChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.addChildAt(obj);
+ });
+ };
}
function testRemoveChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.removeChild(obj);
- });
- fn(function (container, obj)
- {
- container.removeChildAt(container.children.indexOf(obj));
- });
- fn(function (container, obj)
- {
- container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
- });
+ fn(function (container, obj)
+ {
+ container.removeChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildAt(container.children.indexOf(obj));
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
+ });
+ };
}
describe('PIXI.Container', function ()
diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js
index f2e8234..3f47442 100644
--- a/test/core/Ellipse.js
+++ b/test/core/Ellipse.js
@@ -56,6 +56,10 @@
expect(ellipse1.contains(10, 16)).to.be.false;
expect(ellipse1.contains(11, 15)).to.be.false;
expect(ellipse1.contains(0, 0)).to.be.false;
+
+ const ellipse2 = new PIXI.Ellipse(10, 10, 0, 0);
+
+ expect(ellipse2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Matrix.js b/test/core/Matrix.js
index 9d2694b..76bd57c 100644
--- a/test/core/Matrix.js
+++ b/test/core/Matrix.js
@@ -107,10 +107,60 @@
expect(m1.ty).to.equal(m2.ty);
});
+ it('should prepend matrix', function ()
+ {
+ const m1 = new PIXI.Matrix();
+ const m2 = new PIXI.Matrix();
+
+ m2.set(2, 3, 4, 5, 100, 200);
+ m1.prepend(m2);
+
+ expect(m1.a).to.equal(m2.a);
+ expect(m1.b).to.equal(m2.b);
+ expect(m1.c).to.equal(m2.c);
+ expect(m1.d).to.equal(m2.d);
+ expect(m1.tx).to.equal(m2.tx);
+ expect(m1.ty).to.equal(m2.ty);
+
+ const m3 = new PIXI.Matrix();
+ const m4 = new PIXI.Matrix();
+
+ m3.prepend(m4);
+
+ expect(m3.a).to.equal(m4.a);
+ expect(m3.b).to.equal(m4.b);
+ expect(m3.c).to.equal(m4.c);
+ expect(m3.d).to.equal(m4.d);
+ expect(m3.tx).to.equal(m4.tx);
+ expect(m3.ty).to.equal(m4.ty);
+ });
+
it('should get IDENTITY and TEMP_MATRIX', function ()
{
expect(PIXI.Matrix.IDENTITY instanceof PIXI.Matrix).to.be.true;
expect(PIXI.Matrix.TEMP_MATRIX instanceof PIXI.Matrix).to.be.true;
});
-});
+ it('should reset matrix to default when identity() is called', function ()
+ {
+ const matrix = new PIXI.Matrix();
+
+ matrix.set(2, 3, 4, 5, 100, 200);
+
+ expect(matrix.a).to.equal(2);
+ expect(matrix.b).to.equal(3);
+ expect(matrix.c).to.equal(4);
+ expect(matrix.d).to.equal(5);
+ expect(matrix.tx).to.equal(100);
+ expect(matrix.ty).to.equal(200);
+
+ matrix.identity();
+
+ expect(matrix.a).to.equal(1);
+ expect(matrix.b).to.equal(0);
+ expect(matrix.c).to.equal(0);
+ expect(matrix.d).to.equal(1);
+ expect(matrix.tx).to.equal(0);
+ expect(matrix.ty).to.equal(0);
+ });
+});
diff --git a/test/core/Spritesheet.js b/test/core/Spritesheet.js
index 283adf5..7601a0c 100644
--- a/test/core/Spritesheet.js
+++ b/test/core/Spritesheet.js
@@ -18,6 +18,7 @@
expect(textures[id]).to.be.an.instanceof(PIXI.Texture);
expect(textures[id].width).to.equal(spritesheet.data.frames[id].frame.w / spritesheet.resolution);
expect(textures[id].height).to.equal(spritesheet.data.frames[id].frame.h / spritesheet.resolution);
+ expect(textures[id].textureCacheId).to.equal(id);
spritesheet.destroy(true);
expect(spritesheet.textures).to.be.null;
expect(spritesheet.baseTexture).to.be.null;
diff --git a/test/core/Texture.js b/test/core/Texture.js
index 8c4ef98..241ec3e 100644
--- a/test/core/Texture.js
+++ b/test/core/Texture.js
@@ -16,4 +16,20 @@
expect(PIXI.utils.TextureCache[URL]).to.equal(texture);
expect(PIXI.utils.BaseTextureCache[URL]).to.equal(texture.baseTexture);
});
+
+ it('should remove Texture from cache on destroy', function ()
+ {
+ const NAME = 'foo';
+ const NAME2 = 'bar';
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+
+ PIXI.Texture.addTextureToCache(texture, NAME);
+ PIXI.Texture.addTextureToCache(texture, NAME2);
+ expect(texture.textureCacheId).to.equal(NAME);
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(texture);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(undefined);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(undefined);
+ });
});
diff --git a/test/core/Ticker.js b/test/core/Ticker.js
new file mode 100644
index 0000000..188770f
--- /dev/null
+++ b/test/core/Ticker.js
@@ -0,0 +1,322 @@
+'use strict';
+
+const Ticker = PIXI.ticker.Ticker;
+const shared = PIXI.ticker.shared;
+
+describe('PIXI.ticker.Ticker', function ()
+{
+ before(function ()
+ {
+ this.length = (ticker) =>
+ {
+ ticker = ticker || shared;
+
+ if (!ticker._head || !ticker._head.next)
+ {
+ return 0;
+ }
+
+ let listener = ticker._head.next;
+ let i = 0;
+
+ while (listener)
+ {
+ listener = listener.next;
+ i++;
+ }
+
+ return i;
+ };
+ });
+
+ it('should be available', function ()
+ {
+ expect(Ticker).to.be.a.function;
+ expect(shared).to.be.an.instanceof(Ticker);
+ });
+
+ it('should create a new ticker and destroy it', function ()
+ {
+ const ticker = new Ticker();
+
+ ticker.start();
+
+ const listener = sinon.spy();
+
+ expect(this.length(ticker)).to.equal(0);
+
+ ticker.add(listener);
+
+ expect(this.length(ticker)).to.equal(1);
+
+ ticker.destroy();
+
+ expect(ticker._head).to.be.null;
+ expect(ticker.started).to.be.false;
+ expect(this.length(ticker)).to.equal(0);
+ });
+
+ it('should protect destroying shared ticker', function ()
+ {
+ shared.destroy();
+ expect(shared._head).to.not.be.null;
+ expect(shared.started).to.be.true;
+ });
+
+ it('should add and remove listener', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener);
+
+ expect(this.length()).to.equal(length + 1);
+
+ shared.remove(listener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should update a listener', function ()
+ {
+ const listener = sinon.spy();
+
+ shared.add(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ });
+
+ it('should update a listener twice and remove once', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener).add(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length + 2);
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should respect priority order', function ()
+ {
+ const length = this.length();
+ const listener1 = sinon.spy();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.LOW)
+ .add(listener4, null, PIXI.UPDATE_PRIORITY.INTERACTION)
+ .add(listener3, null, PIXI.UPDATE_PRIORITY.HIGH)
+ .add(listener2, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 4);
+
+ sinon.assert.callOrder(listener4, listener3, listener2, listener1);
+
+ shared.remove(listener1)
+ .remove(listener2)
+ .remove(listener3)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should auto-remove once listeners', function ()
+ {
+ const length = this.length();
+ const listener = sinon.spy();
+
+ shared.addOnce(listener);
+
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should call inserted item with a lower priority', function ()
+ {
+ const length = this.length();
+ const lowListener = sinon.spy();
+ const highListener = sinon.spy();
+ const mainListener = sinon.spy(() =>
+ {
+ shared.add(highListener, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(lowListener, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(mainListener, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 3);
+
+ expect(mainListener.calledOnce).to.be.true;
+ expect(lowListener.calledOnce).to.be.true;
+ expect(highListener.calledOnce).to.be.false;
+
+ shared.remove(mainListener)
+ .remove(highListener)
+ .remove(lowListener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove emit low-priority item during emit', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself on emit after adding new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.remove(listener1);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself before, still calling new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener1);
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove items before and after current priority', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(listener3, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.add(listener4, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener2)
+ .remove(listener3);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 2);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.update();
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledTwice).to.be.true;
+ expect(listener1.calledTwice).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should destroy on listener', function (done)
+ {
+ const ticker = new Ticker();
+ const listener2 = sinon.spy();
+ const listener = sinon.spy(() =>
+ {
+ ticker.destroy();
+ setTimeout(() =>
+ {
+ expect(listener2.called).to.be.false;
+ expect(listener.calledOnce).to.be.true;
+ done();
+ }, 0);
+ });
+
+ ticker.add(listener);
+ ticker.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ ticker.start();
+ });
+});
diff --git a/test/core/TilingSprite.js b/test/core/TilingSprite.js
index 2e449a7..7694792 100644
--- a/test/core/TilingSprite.js
+++ b/test/core/TilingSprite.js
@@ -24,4 +24,25 @@
expect(bounds.height).to.equal(600);
});
});
+
+ it('checks if tilingSprite contains a point', function ()
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+ const tilingSprite = new PIXI.extras.TilingSprite(texture, 200, 300);
+
+ expect(tilingSprite.containsPoint(new PIXI.Point(1, 1))).to.equal(true);
+ expect(tilingSprite.containsPoint(new PIXI.Point(300, 400))).to.equal(false);
+ });
+
+ it('gets and sets height and width correctly', function ()
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+ const tilingSprite = new PIXI.extras.TilingSprite(texture, 200, 300);
+
+ tilingSprite.width = 400;
+ tilingSprite.height = 600;
+
+ expect(tilingSprite.width).to.equal(400);
+ expect(tilingSprite.height).to.equal(600);
+ });
});
diff --git a/test/core/index.js b/test/core/index.js
index 8530131..58dc30e 100755
--- a/test/core/index.js
+++ b/test/core/index.js
@@ -17,6 +17,7 @@
require('./util');
require('./Plane');
require('./Point');
+require('./Polygon');
require('./ObservablePoint');
require('./Matrix');
require('./Rectangle');
@@ -27,4 +28,5 @@
require('./WebGLRenderer');
require('./Ellipse');
require('./Texture');
+require('./Ticker');
require('./filters');
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 0e7e707..31385b9 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -4,6 +4,16 @@
describe('PIXI.interaction.InteractionManager', function ()
{
+ afterEach(function ()
+ {
+ // if we made a MockPointer for the test, clean it up
+ if (this.pointer)
+ {
+ this.pointer.cleanUp();
+ this.pointer = null;
+ }
+ });
+
describe('event basics', function ()
{
it('should call mousedown handler', function ()
@@ -11,7 +21,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -29,7 +39,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -47,7 +57,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -66,7 +76,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -84,7 +94,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -286,7 +296,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -304,7 +314,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -316,6 +326,29 @@
expect(clickSpy).to.not.have.been.called;
});
+
+ it('should not call handler when mousedown not received', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const clickSpy = sinon.spy();
+ const pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+ graphics.on('click', clickSpy);
+
+ pointer.mouseup(10, 10);
+
+ expect(clickSpy, 'click should not happen on first mouseup').to.not.have.been.called;
+
+ // test again, just because it was a bug that was reported
+ pointer.mouseup(20, 20);
+
+ expect(clickSpy, 'click should not happen on second mouseup').to.not.have.been.called;
+ });
});
describe('onTap', function ()
@@ -325,7 +358,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -343,7 +376,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -359,32 +392,62 @@
describe('overlapping children', function ()
{
- function getScene(callbackEventName)
+ function getScene(callbackEventName, splitParents)
{
const behindChild = new PIXI.Graphics();
const frontChild = new PIXI.Graphics();
const parent = new PIXI.Container();
- const behindChildCallback = sinon.spy();
- const frontChildCallback = sinon.spy();
- const parentCallback = sinon.spy();
+ const behindChildCallback = sinon.spy(function behindSpy() { /* no op*/ });
+ const frontChildCallback = sinon.spy(function frontSpy() { /* no op*/ });
+ const parentCallback = sinon.spy(function parentSpy() { /* no op*/ });
+ let behindParent;
+ let frontParent;
+ let behindParentCallback;
+ let frontParentCallback;
behindChild.beginFill(0xFF);
behindChild.drawRect(0, 0, 50, 50);
behindChild.on(callbackEventName, behindChildCallback);
+ behindChild.name = 'behind';
frontChild.beginFill(0x00FF);
frontChild.drawRect(0, 0, 50, 50);
frontChild.on(callbackEventName, frontChildCallback);
+ frontChild.name = 'front';
- parent.addChild(behindChild, frontChild);
+ if (splitParents)
+ {
+ behindParent = new PIXI.Container();
+ behindParent.name = 'behindParent';
+ frontParent = new PIXI.Container();
+ frontParent.name = 'frontParent';
+ behindParentCallback = sinon.spy(function behindParentSpy() { /* no op*/ });
+ frontParentCallback = sinon.spy(function frontParentSpy() { /* no op*/ });
+ behindParent.on(callbackEventName, behindParentCallback);
+ frontParent.on(callbackEventName, frontParentCallback);
+
+ parent.addChild(behindParent, frontParent);
+ behindParent.addChild(behindChild);
+ frontParent.addChild(frontChild);
+
+ parent.name = 'parent';
+ }
+ else
+ {
+ parent.addChild(behindChild, frontChild);
+ }
parent.on(callbackEventName, parentCallback);
return {
behindChild,
frontChild,
+ behindParent,
+ frontParent,
parent,
behindChildCallback,
frontChildCallback,
+ behindParentCallback,
+ frontParentCallback,
parentCallback,
};
}
@@ -396,7 +459,7 @@
it('should callback front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -414,7 +477,7 @@
it('should callback front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -432,7 +495,7 @@
it('should callback behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -446,6 +509,48 @@
expect(scene.behindChildCallback).to.have.been.calledOnce;
expect(scene.parentCallback).to.not.have.been.called;
});
+
+ it('should callback front child of different non-interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.not.have.been.called;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.not.have.been.called;
+ });
+
+ it('should callback front child of different interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+ scene.behindParent.interactive = true;
+ scene.frontParent.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.not.have.been.called;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.have.been.calledOnce;
+ });
});
describe('when front child is non-interactive', function ()
@@ -453,7 +558,7 @@
it('should not callback when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -470,7 +575,7 @@
it('should callback behind child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -487,7 +592,7 @@
it('should callback behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -507,7 +612,7 @@
it('should callback front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -524,7 +629,7 @@
it('should callback front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -541,7 +646,7 @@
it('should not callback when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -564,7 +669,7 @@
it('should callback parent and front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -583,7 +688,7 @@
it('should callback parent and front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -602,7 +707,7 @@
it('should callback parent and behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -617,6 +722,50 @@
expect(scene.behindChildCallback).to.have.been.calledOnce;
expect(scene.parentCallback).to.have.been.calledOnce;
});
+
+ it('should callback front child of different non-interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+ scene.parent.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.have.been.calledOnce;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.not.have.been.called;
+ });
+
+ it('should callback front child of different interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+ scene.parent.interactive = true;
+ scene.behindParent.interactive = true;
+ scene.frontParent.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.have.been.calledOnce;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.have.been.calledOnce;
+ });
});
describe('when front child is non-interactive', function ()
@@ -624,7 +773,7 @@
it('should callback parent when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -642,7 +791,7 @@
it('should callback parent and behind child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -660,7 +809,7 @@
it('should callback parent and behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -681,7 +830,7 @@
it('should callback parent and front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -699,7 +848,7 @@
it('should callback parent and front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -717,7 +866,7 @@
it('should callback parent when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -733,6 +882,42 @@
});
});
});
+
+ it('Semi-complicated nesting with overlap, should not call behind callback', function ()
+ {
+ const stage = new PIXI.Container();
+ const frontParent = new PIXI.Container();
+ const frontChild = new PIXI.Graphics();
+ const behindParent = new PIXI.Container();
+ const subParent = new PIXI.Container();
+ const behindChild = new PIXI.Graphics();
+ const behindCallback = sinon.spy(function behindSpy() { /* no op*/ });
+ const frontCallback = sinon.spy(function frontSpy() { /* no op*/ });
+
+ behindChild.beginFill(0xFF);
+ behindChild.drawRect(0, 0, 50, 50);
+ subParent.on('click', behindCallback);
+
+ frontChild.beginFill(0x00FF);
+ frontChild.drawRect(0, 0, 50, 50);
+ frontParent.on('click', frontCallback);
+ const pointer = this.pointer = new MockPointer(stage);
+
+ behindParent.x = 25;
+ subParent.interactive = true;
+ frontParent.interactive = true;
+
+ behindParent.addChild(subParent);
+ subParent.addChild(behindChild);
+ stage.addChild(behindParent);
+ frontParent.addChild(frontChild);
+ stage.addChild(frontParent);
+
+ pointer.click(40, 10);
+
+ expect(behindCallback).to.not.have.been.called;
+ expect(frontCallback).to.have.been.calledOnce;
+ });
});
describe('cursor changes', function ()
@@ -741,7 +926,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -759,7 +944,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -778,7 +963,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -797,7 +982,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -818,7 +1003,7 @@
const graphics = new PIXI.Graphics();
const overSpy = sinon.spy();
const defaultSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -840,7 +1025,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const defaultSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -859,7 +1044,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -881,7 +1066,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -932,7 +1117,7 @@
it('should stop hitTesting after first hit', function ()
{
const scene = getScene();
- const pointer = new MockPointer(scene.stage);
+ const pointer = this.pointer = new MockPointer(scene.stage);
const frontHitTest = sinon.spy(scene.frontChild, 'containsPoint');
const middleHitTest = sinon.spy(scene.middleChild, 'containsPoint');
const behindHitTest = sinon.spy(scene.behindChild, 'containsPoint');
@@ -954,7 +1139,7 @@
it('should stop hitTesting after first hit', function ()
{
const scene = getScene();
- const pointer = new MockPointer(scene.stage);
+ const pointer = this.pointer = new MockPointer(scene.stage);
const frontHitTest = sinon.spy(scene.frontChild, 'containsPoint');
const middleHitTest = sinon.spy(scene.middleChild, 'containsPoint');
const behindHitTest = sinon.spy(scene.behindChild, 'containsPoint');
@@ -971,4 +1156,127 @@
});
});
});
+
+ describe('pointer handling', function ()
+ {
+ it('pointer event from mouse should use single mouse data', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage, 100, 100, true);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.mousemove(20, 10, true);
+
+ expect(pointer.interaction.mouse.global.x).to.equal(20);
+ expect(pointer.interaction.mouse.global.y).to.equal(10);
+ });
+ });
+
+ describe('data cleanup', function ()
+ {
+ it('touchleave after touchout should not orphan data', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.touchstart(10, 10, 42);
+ expect(pointer.interaction.activeInteractionData[42]).to.exist;
+ pointer.touchend(10, 10, 42);
+ expect(pointer.interaction.activeInteractionData[42]).to.be.undefined;
+ pointer.touchleave(10, 10, 42);
+ expect(pointer.interaction.activeInteractionData[42]).to.be.undefined;
+ });
+ });
+
+ describe('hitTest()', function ()
+ {
+ it('should return hit', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(10, 10));
+
+ expect(hit).to.equal(graphics);
+ });
+
+ it('should return null if not hit', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(60, 60));
+
+ expect(hit).to.be.null;
+ });
+
+ it('should return top thing that was hit', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const behind = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(behind);
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+ behind.beginFill(0xFFFFFF);
+ behind.drawRect(0, 0, 50, 50);
+ behind.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(10, 10));
+
+ expect(hit).to.equal(graphics);
+ });
+
+ it('should return hit when passing in root', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const behind = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(behind);
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+ behind.beginFill(0xFFFFFF);
+ behind.drawRect(0, 0, 50, 50);
+ behind.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(10, 10), behind);
+
+ expect(hit).to.equal(behind);
+ });
+ });
});
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/test/core/Circle.js b/test/core/Circle.js
index 183f98f..f621992 100644
--- a/test/core/Circle.js
+++ b/test/core/Circle.js
@@ -53,6 +53,10 @@
expect(circ1.contains(10, 16)).to.be.false;
expect(circ1.contains(11, 15)).to.be.false;
expect(circ1.contains(0, 0)).to.be.false;
+
+ const circ2 = new PIXI.Circle(10, 10, 0);
+
+ expect(circ2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Container.js b/test/core/Container.js
index d11be33..cefde54 100644
--- a/test/core/Container.js
+++ b/test/core/Container.js
@@ -2,30 +2,36 @@
function testAddChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.addChild(obj);
- });
- fn(function (container, obj)
- {
- container.addChildAt(obj);
- });
+ fn(function (container, obj)
+ {
+ container.addChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.addChildAt(obj);
+ });
+ };
}
function testRemoveChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.removeChild(obj);
- });
- fn(function (container, obj)
- {
- container.removeChildAt(container.children.indexOf(obj));
- });
- fn(function (container, obj)
- {
- container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
- });
+ fn(function (container, obj)
+ {
+ container.removeChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildAt(container.children.indexOf(obj));
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
+ });
+ };
}
describe('PIXI.Container', function ()
diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js
index f2e8234..3f47442 100644
--- a/test/core/Ellipse.js
+++ b/test/core/Ellipse.js
@@ -56,6 +56,10 @@
expect(ellipse1.contains(10, 16)).to.be.false;
expect(ellipse1.contains(11, 15)).to.be.false;
expect(ellipse1.contains(0, 0)).to.be.false;
+
+ const ellipse2 = new PIXI.Ellipse(10, 10, 0, 0);
+
+ expect(ellipse2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Matrix.js b/test/core/Matrix.js
index 9d2694b..76bd57c 100644
--- a/test/core/Matrix.js
+++ b/test/core/Matrix.js
@@ -107,10 +107,60 @@
expect(m1.ty).to.equal(m2.ty);
});
+ it('should prepend matrix', function ()
+ {
+ const m1 = new PIXI.Matrix();
+ const m2 = new PIXI.Matrix();
+
+ m2.set(2, 3, 4, 5, 100, 200);
+ m1.prepend(m2);
+
+ expect(m1.a).to.equal(m2.a);
+ expect(m1.b).to.equal(m2.b);
+ expect(m1.c).to.equal(m2.c);
+ expect(m1.d).to.equal(m2.d);
+ expect(m1.tx).to.equal(m2.tx);
+ expect(m1.ty).to.equal(m2.ty);
+
+ const m3 = new PIXI.Matrix();
+ const m4 = new PIXI.Matrix();
+
+ m3.prepend(m4);
+
+ expect(m3.a).to.equal(m4.a);
+ expect(m3.b).to.equal(m4.b);
+ expect(m3.c).to.equal(m4.c);
+ expect(m3.d).to.equal(m4.d);
+ expect(m3.tx).to.equal(m4.tx);
+ expect(m3.ty).to.equal(m4.ty);
+ });
+
it('should get IDENTITY and TEMP_MATRIX', function ()
{
expect(PIXI.Matrix.IDENTITY instanceof PIXI.Matrix).to.be.true;
expect(PIXI.Matrix.TEMP_MATRIX instanceof PIXI.Matrix).to.be.true;
});
-});
+ it('should reset matrix to default when identity() is called', function ()
+ {
+ const matrix = new PIXI.Matrix();
+
+ matrix.set(2, 3, 4, 5, 100, 200);
+
+ expect(matrix.a).to.equal(2);
+ expect(matrix.b).to.equal(3);
+ expect(matrix.c).to.equal(4);
+ expect(matrix.d).to.equal(5);
+ expect(matrix.tx).to.equal(100);
+ expect(matrix.ty).to.equal(200);
+
+ matrix.identity();
+
+ expect(matrix.a).to.equal(1);
+ expect(matrix.b).to.equal(0);
+ expect(matrix.c).to.equal(0);
+ expect(matrix.d).to.equal(1);
+ expect(matrix.tx).to.equal(0);
+ expect(matrix.ty).to.equal(0);
+ });
+});
diff --git a/test/core/Spritesheet.js b/test/core/Spritesheet.js
index 283adf5..7601a0c 100644
--- a/test/core/Spritesheet.js
+++ b/test/core/Spritesheet.js
@@ -18,6 +18,7 @@
expect(textures[id]).to.be.an.instanceof(PIXI.Texture);
expect(textures[id].width).to.equal(spritesheet.data.frames[id].frame.w / spritesheet.resolution);
expect(textures[id].height).to.equal(spritesheet.data.frames[id].frame.h / spritesheet.resolution);
+ expect(textures[id].textureCacheId).to.equal(id);
spritesheet.destroy(true);
expect(spritesheet.textures).to.be.null;
expect(spritesheet.baseTexture).to.be.null;
diff --git a/test/core/Texture.js b/test/core/Texture.js
index 8c4ef98..241ec3e 100644
--- a/test/core/Texture.js
+++ b/test/core/Texture.js
@@ -16,4 +16,20 @@
expect(PIXI.utils.TextureCache[URL]).to.equal(texture);
expect(PIXI.utils.BaseTextureCache[URL]).to.equal(texture.baseTexture);
});
+
+ it('should remove Texture from cache on destroy', function ()
+ {
+ const NAME = 'foo';
+ const NAME2 = 'bar';
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+
+ PIXI.Texture.addTextureToCache(texture, NAME);
+ PIXI.Texture.addTextureToCache(texture, NAME2);
+ expect(texture.textureCacheId).to.equal(NAME);
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(texture);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(undefined);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(undefined);
+ });
});
diff --git a/test/core/Ticker.js b/test/core/Ticker.js
new file mode 100644
index 0000000..188770f
--- /dev/null
+++ b/test/core/Ticker.js
@@ -0,0 +1,322 @@
+'use strict';
+
+const Ticker = PIXI.ticker.Ticker;
+const shared = PIXI.ticker.shared;
+
+describe('PIXI.ticker.Ticker', function ()
+{
+ before(function ()
+ {
+ this.length = (ticker) =>
+ {
+ ticker = ticker || shared;
+
+ if (!ticker._head || !ticker._head.next)
+ {
+ return 0;
+ }
+
+ let listener = ticker._head.next;
+ let i = 0;
+
+ while (listener)
+ {
+ listener = listener.next;
+ i++;
+ }
+
+ return i;
+ };
+ });
+
+ it('should be available', function ()
+ {
+ expect(Ticker).to.be.a.function;
+ expect(shared).to.be.an.instanceof(Ticker);
+ });
+
+ it('should create a new ticker and destroy it', function ()
+ {
+ const ticker = new Ticker();
+
+ ticker.start();
+
+ const listener = sinon.spy();
+
+ expect(this.length(ticker)).to.equal(0);
+
+ ticker.add(listener);
+
+ expect(this.length(ticker)).to.equal(1);
+
+ ticker.destroy();
+
+ expect(ticker._head).to.be.null;
+ expect(ticker.started).to.be.false;
+ expect(this.length(ticker)).to.equal(0);
+ });
+
+ it('should protect destroying shared ticker', function ()
+ {
+ shared.destroy();
+ expect(shared._head).to.not.be.null;
+ expect(shared.started).to.be.true;
+ });
+
+ it('should add and remove listener', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener);
+
+ expect(this.length()).to.equal(length + 1);
+
+ shared.remove(listener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should update a listener', function ()
+ {
+ const listener = sinon.spy();
+
+ shared.add(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ });
+
+ it('should update a listener twice and remove once', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener).add(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length + 2);
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should respect priority order', function ()
+ {
+ const length = this.length();
+ const listener1 = sinon.spy();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.LOW)
+ .add(listener4, null, PIXI.UPDATE_PRIORITY.INTERACTION)
+ .add(listener3, null, PIXI.UPDATE_PRIORITY.HIGH)
+ .add(listener2, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 4);
+
+ sinon.assert.callOrder(listener4, listener3, listener2, listener1);
+
+ shared.remove(listener1)
+ .remove(listener2)
+ .remove(listener3)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should auto-remove once listeners', function ()
+ {
+ const length = this.length();
+ const listener = sinon.spy();
+
+ shared.addOnce(listener);
+
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should call inserted item with a lower priority', function ()
+ {
+ const length = this.length();
+ const lowListener = sinon.spy();
+ const highListener = sinon.spy();
+ const mainListener = sinon.spy(() =>
+ {
+ shared.add(highListener, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(lowListener, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(mainListener, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 3);
+
+ expect(mainListener.calledOnce).to.be.true;
+ expect(lowListener.calledOnce).to.be.true;
+ expect(highListener.calledOnce).to.be.false;
+
+ shared.remove(mainListener)
+ .remove(highListener)
+ .remove(lowListener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove emit low-priority item during emit', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself on emit after adding new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.remove(listener1);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself before, still calling new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener1);
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove items before and after current priority', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(listener3, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.add(listener4, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener2)
+ .remove(listener3);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 2);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.update();
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledTwice).to.be.true;
+ expect(listener1.calledTwice).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should destroy on listener', function (done)
+ {
+ const ticker = new Ticker();
+ const listener2 = sinon.spy();
+ const listener = sinon.spy(() =>
+ {
+ ticker.destroy();
+ setTimeout(() =>
+ {
+ expect(listener2.called).to.be.false;
+ expect(listener.calledOnce).to.be.true;
+ done();
+ }, 0);
+ });
+
+ ticker.add(listener);
+ ticker.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ ticker.start();
+ });
+});
diff --git a/test/core/TilingSprite.js b/test/core/TilingSprite.js
index 2e449a7..7694792 100644
--- a/test/core/TilingSprite.js
+++ b/test/core/TilingSprite.js
@@ -24,4 +24,25 @@
expect(bounds.height).to.equal(600);
});
});
+
+ it('checks if tilingSprite contains a point', function ()
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+ const tilingSprite = new PIXI.extras.TilingSprite(texture, 200, 300);
+
+ expect(tilingSprite.containsPoint(new PIXI.Point(1, 1))).to.equal(true);
+ expect(tilingSprite.containsPoint(new PIXI.Point(300, 400))).to.equal(false);
+ });
+
+ it('gets and sets height and width correctly', function ()
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+ const tilingSprite = new PIXI.extras.TilingSprite(texture, 200, 300);
+
+ tilingSprite.width = 400;
+ tilingSprite.height = 600;
+
+ expect(tilingSprite.width).to.equal(400);
+ expect(tilingSprite.height).to.equal(600);
+ });
});
diff --git a/test/core/index.js b/test/core/index.js
index 8530131..58dc30e 100755
--- a/test/core/index.js
+++ b/test/core/index.js
@@ -17,6 +17,7 @@
require('./util');
require('./Plane');
require('./Point');
+require('./Polygon');
require('./ObservablePoint');
require('./Matrix');
require('./Rectangle');
@@ -27,4 +28,5 @@
require('./WebGLRenderer');
require('./Ellipse');
require('./Texture');
+require('./Ticker');
require('./filters');
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 0e7e707..31385b9 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -4,6 +4,16 @@
describe('PIXI.interaction.InteractionManager', function ()
{
+ afterEach(function ()
+ {
+ // if we made a MockPointer for the test, clean it up
+ if (this.pointer)
+ {
+ this.pointer.cleanUp();
+ this.pointer = null;
+ }
+ });
+
describe('event basics', function ()
{
it('should call mousedown handler', function ()
@@ -11,7 +21,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -29,7 +39,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -47,7 +57,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -66,7 +76,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -84,7 +94,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -286,7 +296,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -304,7 +314,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -316,6 +326,29 @@
expect(clickSpy).to.not.have.been.called;
});
+
+ it('should not call handler when mousedown not received', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const clickSpy = sinon.spy();
+ const pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+ graphics.on('click', clickSpy);
+
+ pointer.mouseup(10, 10);
+
+ expect(clickSpy, 'click should not happen on first mouseup').to.not.have.been.called;
+
+ // test again, just because it was a bug that was reported
+ pointer.mouseup(20, 20);
+
+ expect(clickSpy, 'click should not happen on second mouseup').to.not.have.been.called;
+ });
});
describe('onTap', function ()
@@ -325,7 +358,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -343,7 +376,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -359,32 +392,62 @@
describe('overlapping children', function ()
{
- function getScene(callbackEventName)
+ function getScene(callbackEventName, splitParents)
{
const behindChild = new PIXI.Graphics();
const frontChild = new PIXI.Graphics();
const parent = new PIXI.Container();
- const behindChildCallback = sinon.spy();
- const frontChildCallback = sinon.spy();
- const parentCallback = sinon.spy();
+ const behindChildCallback = sinon.spy(function behindSpy() { /* no op*/ });
+ const frontChildCallback = sinon.spy(function frontSpy() { /* no op*/ });
+ const parentCallback = sinon.spy(function parentSpy() { /* no op*/ });
+ let behindParent;
+ let frontParent;
+ let behindParentCallback;
+ let frontParentCallback;
behindChild.beginFill(0xFF);
behindChild.drawRect(0, 0, 50, 50);
behindChild.on(callbackEventName, behindChildCallback);
+ behindChild.name = 'behind';
frontChild.beginFill(0x00FF);
frontChild.drawRect(0, 0, 50, 50);
frontChild.on(callbackEventName, frontChildCallback);
+ frontChild.name = 'front';
- parent.addChild(behindChild, frontChild);
+ if (splitParents)
+ {
+ behindParent = new PIXI.Container();
+ behindParent.name = 'behindParent';
+ frontParent = new PIXI.Container();
+ frontParent.name = 'frontParent';
+ behindParentCallback = sinon.spy(function behindParentSpy() { /* no op*/ });
+ frontParentCallback = sinon.spy(function frontParentSpy() { /* no op*/ });
+ behindParent.on(callbackEventName, behindParentCallback);
+ frontParent.on(callbackEventName, frontParentCallback);
+
+ parent.addChild(behindParent, frontParent);
+ behindParent.addChild(behindChild);
+ frontParent.addChild(frontChild);
+
+ parent.name = 'parent';
+ }
+ else
+ {
+ parent.addChild(behindChild, frontChild);
+ }
parent.on(callbackEventName, parentCallback);
return {
behindChild,
frontChild,
+ behindParent,
+ frontParent,
parent,
behindChildCallback,
frontChildCallback,
+ behindParentCallback,
+ frontParentCallback,
parentCallback,
};
}
@@ -396,7 +459,7 @@
it('should callback front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -414,7 +477,7 @@
it('should callback front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -432,7 +495,7 @@
it('should callback behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -446,6 +509,48 @@
expect(scene.behindChildCallback).to.have.been.calledOnce;
expect(scene.parentCallback).to.not.have.been.called;
});
+
+ it('should callback front child of different non-interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.not.have.been.called;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.not.have.been.called;
+ });
+
+ it('should callback front child of different interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+ scene.behindParent.interactive = true;
+ scene.frontParent.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.not.have.been.called;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.have.been.calledOnce;
+ });
});
describe('when front child is non-interactive', function ()
@@ -453,7 +558,7 @@
it('should not callback when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -470,7 +575,7 @@
it('should callback behind child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -487,7 +592,7 @@
it('should callback behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -507,7 +612,7 @@
it('should callback front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -524,7 +629,7 @@
it('should callback front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -541,7 +646,7 @@
it('should not callback when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -564,7 +669,7 @@
it('should callback parent and front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -583,7 +688,7 @@
it('should callback parent and front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -602,7 +707,7 @@
it('should callback parent and behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -617,6 +722,50 @@
expect(scene.behindChildCallback).to.have.been.calledOnce;
expect(scene.parentCallback).to.have.been.calledOnce;
});
+
+ it('should callback front child of different non-interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+ scene.parent.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.have.been.calledOnce;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.not.have.been.called;
+ });
+
+ it('should callback front child of different interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+ scene.parent.interactive = true;
+ scene.behindParent.interactive = true;
+ scene.frontParent.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.have.been.calledOnce;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.have.been.calledOnce;
+ });
});
describe('when front child is non-interactive', function ()
@@ -624,7 +773,7 @@
it('should callback parent when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -642,7 +791,7 @@
it('should callback parent and behind child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -660,7 +809,7 @@
it('should callback parent and behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -681,7 +830,7 @@
it('should callback parent and front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -699,7 +848,7 @@
it('should callback parent and front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -717,7 +866,7 @@
it('should callback parent when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -733,6 +882,42 @@
});
});
});
+
+ it('Semi-complicated nesting with overlap, should not call behind callback', function ()
+ {
+ const stage = new PIXI.Container();
+ const frontParent = new PIXI.Container();
+ const frontChild = new PIXI.Graphics();
+ const behindParent = new PIXI.Container();
+ const subParent = new PIXI.Container();
+ const behindChild = new PIXI.Graphics();
+ const behindCallback = sinon.spy(function behindSpy() { /* no op*/ });
+ const frontCallback = sinon.spy(function frontSpy() { /* no op*/ });
+
+ behindChild.beginFill(0xFF);
+ behindChild.drawRect(0, 0, 50, 50);
+ subParent.on('click', behindCallback);
+
+ frontChild.beginFill(0x00FF);
+ frontChild.drawRect(0, 0, 50, 50);
+ frontParent.on('click', frontCallback);
+ const pointer = this.pointer = new MockPointer(stage);
+
+ behindParent.x = 25;
+ subParent.interactive = true;
+ frontParent.interactive = true;
+
+ behindParent.addChild(subParent);
+ subParent.addChild(behindChild);
+ stage.addChild(behindParent);
+ frontParent.addChild(frontChild);
+ stage.addChild(frontParent);
+
+ pointer.click(40, 10);
+
+ expect(behindCallback).to.not.have.been.called;
+ expect(frontCallback).to.have.been.calledOnce;
+ });
});
describe('cursor changes', function ()
@@ -741,7 +926,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -759,7 +944,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -778,7 +963,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -797,7 +982,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -818,7 +1003,7 @@
const graphics = new PIXI.Graphics();
const overSpy = sinon.spy();
const defaultSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -840,7 +1025,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const defaultSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -859,7 +1044,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -881,7 +1066,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -932,7 +1117,7 @@
it('should stop hitTesting after first hit', function ()
{
const scene = getScene();
- const pointer = new MockPointer(scene.stage);
+ const pointer = this.pointer = new MockPointer(scene.stage);
const frontHitTest = sinon.spy(scene.frontChild, 'containsPoint');
const middleHitTest = sinon.spy(scene.middleChild, 'containsPoint');
const behindHitTest = sinon.spy(scene.behindChild, 'containsPoint');
@@ -954,7 +1139,7 @@
it('should stop hitTesting after first hit', function ()
{
const scene = getScene();
- const pointer = new MockPointer(scene.stage);
+ const pointer = this.pointer = new MockPointer(scene.stage);
const frontHitTest = sinon.spy(scene.frontChild, 'containsPoint');
const middleHitTest = sinon.spy(scene.middleChild, 'containsPoint');
const behindHitTest = sinon.spy(scene.behindChild, 'containsPoint');
@@ -971,4 +1156,127 @@
});
});
});
+
+ describe('pointer handling', function ()
+ {
+ it('pointer event from mouse should use single mouse data', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage, 100, 100, true);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.mousemove(20, 10, true);
+
+ expect(pointer.interaction.mouse.global.x).to.equal(20);
+ expect(pointer.interaction.mouse.global.y).to.equal(10);
+ });
+ });
+
+ describe('data cleanup', function ()
+ {
+ it('touchleave after touchout should not orphan data', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.touchstart(10, 10, 42);
+ expect(pointer.interaction.activeInteractionData[42]).to.exist;
+ pointer.touchend(10, 10, 42);
+ expect(pointer.interaction.activeInteractionData[42]).to.be.undefined;
+ pointer.touchleave(10, 10, 42);
+ expect(pointer.interaction.activeInteractionData[42]).to.be.undefined;
+ });
+ });
+
+ describe('hitTest()', function ()
+ {
+ it('should return hit', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(10, 10));
+
+ expect(hit).to.equal(graphics);
+ });
+
+ it('should return null if not hit', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(60, 60));
+
+ expect(hit).to.be.null;
+ });
+
+ it('should return top thing that was hit', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const behind = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(behind);
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+ behind.beginFill(0xFFFFFF);
+ behind.drawRect(0, 0, 50, 50);
+ behind.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(10, 10));
+
+ expect(hit).to.equal(graphics);
+ });
+
+ it('should return hit when passing in root', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const behind = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(behind);
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+ behind.beginFill(0xFFFFFF);
+ behind.drawRect(0, 0, 50, 50);
+ behind.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(10, 10), behind);
+
+ expect(hit).to.equal(behind);
+ });
+ });
});
diff --git a/test/interaction/MockPointer.js b/test/interaction/MockPointer.js
index 67878af..c9c6228 100644
--- a/test/interaction/MockPointer.js
+++ b/test/interaction/MockPointer.js
@@ -11,13 +11,43 @@
* @param {PIXI.Container} stage - The root of the scene tree
* @param {number} [width=100] - Width of the renderer
* @param {number} [height=100] - Height of the renderer
+ * @param {boolean} [ensurePointerEvents=false] - If we should make sure that PointerEvents are 'supported'
*/
- constructor(stage, width, height)
+ constructor(stage, width, height, ensurePointerEvents)
{
+ // fake PointerEvent existing
+ if (ensurePointerEvents && !window.PointerEvent)
+ {
+ window.PointerEvent = class PointerEvent extends MouseEvent
+ {
+ //eslint-disable-next-line
+ constructor(type, opts)
+ {
+ super(type, opts);
+ this.pointerType = opts.pointerType;
+ }
+ };
+ this.createdPointerEvent = true;
+ }
+
this.stage = stage;
this.renderer = new PIXI.CanvasRenderer(width || 100, height || 100);
this.renderer.sayHello = () => { /* empty */ };
this.interaction = this.renderer.plugins.interaction;
+ this.interaction.supportsTouchEvents = true;
+ PIXI.ticker.shared.remove(this.interaction.update, this.interaction);
+ }
+
+ /**
+ * Cleans up after tests
+ */
+ cleanup()
+ {
+ if (this.createdPointerEvent)
+ {
+ delete window.PointerEvent;
+ }
+ this.renderer.destroy();
}
/**
@@ -45,14 +75,29 @@
/**
* @param {number} x - pointer x position
* @param {number} y - pointer y position
+ * @param {boolean} [asPointer] - if it should be a PointerEvent from a mouse
*/
- mousemove(x, y)
+ mousemove(x, y, asPointer)
{
- const mouseEvent = new MouseEvent('mousemove', {
- clientX: x,
- clientY: y,
- preventDefault: sinon.stub(),
- });
+ let mouseEvent;
+
+ if (asPointer)
+ {
+ mouseEvent = new PointerEvent('pointermove', {
+ pointerType: 'mouse',
+ clientX: x,
+ clientY: y,
+ preventDefault: sinon.stub(),
+ });
+ }
+ else
+ {
+ mouseEvent = new MouseEvent('mousemove', {
+ clientX: x,
+ clientY: y,
+ preventDefault: sinon.stub(),
+ });
+ }
this.setPosition(x, y);
this.render();
@@ -97,9 +142,15 @@
*/
mousedown(x, y)
{
+ const mouseEvent = new MouseEvent('mousedown', {
+ clientX: x,
+ clientY: y,
+ preventDefault: sinon.stub(),
+ });
+
this.setPosition(x, y);
this.render();
- this.interaction.onMouseDown({ clientX: 0, clientY: 0, preventDefault: sinon.stub() });
+ this.interaction.onPointerDown(mouseEvent);
}
/**
@@ -108,47 +159,83 @@
*/
mouseup(x, y)
{
- this.setPosition(x, y);
- this.render();
- this.interaction.onMouseUp({ clientX: 0, clientY: 0, preventDefault: sinon.stub() });
- }
-
- /**
- * @param {number} x - pointer x position
- * @param {number} y - pointer y position
- */
- tap(x, y)
- {
- this.touchstart(x, y);
- this.touchend(x, y);
- }
-
- /**
- * @param {number} x - pointer x position
- * @param {number} y - pointer y position
- */
- touchstart(x, y)
- {
- this.setPosition(x, y);
- this.render();
- this.interaction.onTouchStart({
+ const mouseEvent = new MouseEvent('mouseup', {
+ clientX: x,
+ clientY: y,
preventDefault: sinon.stub(),
- changedTouches: [new Touch({ identifier: 0, target: this.renderer.view })],
});
+
+ this.setPosition(x, y);
+ this.render();
+ this.interaction.onPointerUp(mouseEvent);
}
/**
* @param {number} x - pointer x position
* @param {number} y - pointer y position
+ * @param {number} [identifier] - pointer id
*/
- touchend(x, y)
+ tap(x, y, identifier)
{
+ this.touchstart(x, y, identifier);
+ this.touchend(x, y, identifier);
+ }
+
+ /**
+ * @param {number} x - pointer x position
+ * @param {number} y - pointer y position
+ * @param {number} [identifier] - pointer id
+ */
+ touchstart(x, y, identifier)
+ {
+ const touchEvent = new TouchEvent('touchstart', {
+ preventDefault: sinon.stub(),
+ changedTouches: [
+ new Touch({ identifier: identifier || 0, target: this.renderer.view }),
+ ],
+ });
+
this.setPosition(x, y);
this.render();
- this.interaction.onTouchEnd({
+ this.interaction.onPointerDown(touchEvent);
+ }
+
+ /**
+ * @param {number} x - pointer x position
+ * @param {number} y - pointer y position
+ * @param {number} [identifier] - pointer id
+ */
+ touchend(x, y, identifier)
+ {
+ const touchEvent = new TouchEvent('touchend', {
preventDefault: sinon.stub(),
- changedTouches: [new Touch({ identifier: 0, target: this.renderer.view })],
+ changedTouches: [
+ new Touch({ identifier: identifier || 0, target: this.renderer.view }),
+ ],
});
+
+ this.setPosition(x, y);
+ this.render();
+ this.interaction.onPointerUp(touchEvent);
+ }
+
+ /**
+ * @param {number} x - pointer x position
+ * @param {number} y - pointer y position
+ * @param {number} [identifier] - pointer id
+ */
+ touchleave(x, y, identifier)
+ {
+ const touchEvent = new TouchEvent('touchleave', {
+ preventDefault: sinon.stub(),
+ changedTouches: [
+ new Touch({ identifier: identifier || 0, target: this.renderer.view }),
+ ],
+ });
+
+ this.setPosition(x, y);
+ this.render();
+ this.interaction.onPointerOut(touchEvent);
}
}
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/test/core/Circle.js b/test/core/Circle.js
index 183f98f..f621992 100644
--- a/test/core/Circle.js
+++ b/test/core/Circle.js
@@ -53,6 +53,10 @@
expect(circ1.contains(10, 16)).to.be.false;
expect(circ1.contains(11, 15)).to.be.false;
expect(circ1.contains(0, 0)).to.be.false;
+
+ const circ2 = new PIXI.Circle(10, 10, 0);
+
+ expect(circ2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Container.js b/test/core/Container.js
index d11be33..cefde54 100644
--- a/test/core/Container.js
+++ b/test/core/Container.js
@@ -2,30 +2,36 @@
function testAddChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.addChild(obj);
- });
- fn(function (container, obj)
- {
- container.addChildAt(obj);
- });
+ fn(function (container, obj)
+ {
+ container.addChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.addChildAt(obj);
+ });
+ };
}
function testRemoveChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.removeChild(obj);
- });
- fn(function (container, obj)
- {
- container.removeChildAt(container.children.indexOf(obj));
- });
- fn(function (container, obj)
- {
- container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
- });
+ fn(function (container, obj)
+ {
+ container.removeChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildAt(container.children.indexOf(obj));
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
+ });
+ };
}
describe('PIXI.Container', function ()
diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js
index f2e8234..3f47442 100644
--- a/test/core/Ellipse.js
+++ b/test/core/Ellipse.js
@@ -56,6 +56,10 @@
expect(ellipse1.contains(10, 16)).to.be.false;
expect(ellipse1.contains(11, 15)).to.be.false;
expect(ellipse1.contains(0, 0)).to.be.false;
+
+ const ellipse2 = new PIXI.Ellipse(10, 10, 0, 0);
+
+ expect(ellipse2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Matrix.js b/test/core/Matrix.js
index 9d2694b..76bd57c 100644
--- a/test/core/Matrix.js
+++ b/test/core/Matrix.js
@@ -107,10 +107,60 @@
expect(m1.ty).to.equal(m2.ty);
});
+ it('should prepend matrix', function ()
+ {
+ const m1 = new PIXI.Matrix();
+ const m2 = new PIXI.Matrix();
+
+ m2.set(2, 3, 4, 5, 100, 200);
+ m1.prepend(m2);
+
+ expect(m1.a).to.equal(m2.a);
+ expect(m1.b).to.equal(m2.b);
+ expect(m1.c).to.equal(m2.c);
+ expect(m1.d).to.equal(m2.d);
+ expect(m1.tx).to.equal(m2.tx);
+ expect(m1.ty).to.equal(m2.ty);
+
+ const m3 = new PIXI.Matrix();
+ const m4 = new PIXI.Matrix();
+
+ m3.prepend(m4);
+
+ expect(m3.a).to.equal(m4.a);
+ expect(m3.b).to.equal(m4.b);
+ expect(m3.c).to.equal(m4.c);
+ expect(m3.d).to.equal(m4.d);
+ expect(m3.tx).to.equal(m4.tx);
+ expect(m3.ty).to.equal(m4.ty);
+ });
+
it('should get IDENTITY and TEMP_MATRIX', function ()
{
expect(PIXI.Matrix.IDENTITY instanceof PIXI.Matrix).to.be.true;
expect(PIXI.Matrix.TEMP_MATRIX instanceof PIXI.Matrix).to.be.true;
});
-});
+ it('should reset matrix to default when identity() is called', function ()
+ {
+ const matrix = new PIXI.Matrix();
+
+ matrix.set(2, 3, 4, 5, 100, 200);
+
+ expect(matrix.a).to.equal(2);
+ expect(matrix.b).to.equal(3);
+ expect(matrix.c).to.equal(4);
+ expect(matrix.d).to.equal(5);
+ expect(matrix.tx).to.equal(100);
+ expect(matrix.ty).to.equal(200);
+
+ matrix.identity();
+
+ expect(matrix.a).to.equal(1);
+ expect(matrix.b).to.equal(0);
+ expect(matrix.c).to.equal(0);
+ expect(matrix.d).to.equal(1);
+ expect(matrix.tx).to.equal(0);
+ expect(matrix.ty).to.equal(0);
+ });
+});
diff --git a/test/core/Spritesheet.js b/test/core/Spritesheet.js
index 283adf5..7601a0c 100644
--- a/test/core/Spritesheet.js
+++ b/test/core/Spritesheet.js
@@ -18,6 +18,7 @@
expect(textures[id]).to.be.an.instanceof(PIXI.Texture);
expect(textures[id].width).to.equal(spritesheet.data.frames[id].frame.w / spritesheet.resolution);
expect(textures[id].height).to.equal(spritesheet.data.frames[id].frame.h / spritesheet.resolution);
+ expect(textures[id].textureCacheId).to.equal(id);
spritesheet.destroy(true);
expect(spritesheet.textures).to.be.null;
expect(spritesheet.baseTexture).to.be.null;
diff --git a/test/core/Texture.js b/test/core/Texture.js
index 8c4ef98..241ec3e 100644
--- a/test/core/Texture.js
+++ b/test/core/Texture.js
@@ -16,4 +16,20 @@
expect(PIXI.utils.TextureCache[URL]).to.equal(texture);
expect(PIXI.utils.BaseTextureCache[URL]).to.equal(texture.baseTexture);
});
+
+ it('should remove Texture from cache on destroy', function ()
+ {
+ const NAME = 'foo';
+ const NAME2 = 'bar';
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+
+ PIXI.Texture.addTextureToCache(texture, NAME);
+ PIXI.Texture.addTextureToCache(texture, NAME2);
+ expect(texture.textureCacheId).to.equal(NAME);
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(texture);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(undefined);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(undefined);
+ });
});
diff --git a/test/core/Ticker.js b/test/core/Ticker.js
new file mode 100644
index 0000000..188770f
--- /dev/null
+++ b/test/core/Ticker.js
@@ -0,0 +1,322 @@
+'use strict';
+
+const Ticker = PIXI.ticker.Ticker;
+const shared = PIXI.ticker.shared;
+
+describe('PIXI.ticker.Ticker', function ()
+{
+ before(function ()
+ {
+ this.length = (ticker) =>
+ {
+ ticker = ticker || shared;
+
+ if (!ticker._head || !ticker._head.next)
+ {
+ return 0;
+ }
+
+ let listener = ticker._head.next;
+ let i = 0;
+
+ while (listener)
+ {
+ listener = listener.next;
+ i++;
+ }
+
+ return i;
+ };
+ });
+
+ it('should be available', function ()
+ {
+ expect(Ticker).to.be.a.function;
+ expect(shared).to.be.an.instanceof(Ticker);
+ });
+
+ it('should create a new ticker and destroy it', function ()
+ {
+ const ticker = new Ticker();
+
+ ticker.start();
+
+ const listener = sinon.spy();
+
+ expect(this.length(ticker)).to.equal(0);
+
+ ticker.add(listener);
+
+ expect(this.length(ticker)).to.equal(1);
+
+ ticker.destroy();
+
+ expect(ticker._head).to.be.null;
+ expect(ticker.started).to.be.false;
+ expect(this.length(ticker)).to.equal(0);
+ });
+
+ it('should protect destroying shared ticker', function ()
+ {
+ shared.destroy();
+ expect(shared._head).to.not.be.null;
+ expect(shared.started).to.be.true;
+ });
+
+ it('should add and remove listener', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener);
+
+ expect(this.length()).to.equal(length + 1);
+
+ shared.remove(listener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should update a listener', function ()
+ {
+ const listener = sinon.spy();
+
+ shared.add(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ });
+
+ it('should update a listener twice and remove once', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener).add(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length + 2);
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should respect priority order', function ()
+ {
+ const length = this.length();
+ const listener1 = sinon.spy();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.LOW)
+ .add(listener4, null, PIXI.UPDATE_PRIORITY.INTERACTION)
+ .add(listener3, null, PIXI.UPDATE_PRIORITY.HIGH)
+ .add(listener2, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 4);
+
+ sinon.assert.callOrder(listener4, listener3, listener2, listener1);
+
+ shared.remove(listener1)
+ .remove(listener2)
+ .remove(listener3)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should auto-remove once listeners', function ()
+ {
+ const length = this.length();
+ const listener = sinon.spy();
+
+ shared.addOnce(listener);
+
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should call inserted item with a lower priority', function ()
+ {
+ const length = this.length();
+ const lowListener = sinon.spy();
+ const highListener = sinon.spy();
+ const mainListener = sinon.spy(() =>
+ {
+ shared.add(highListener, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(lowListener, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(mainListener, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 3);
+
+ expect(mainListener.calledOnce).to.be.true;
+ expect(lowListener.calledOnce).to.be.true;
+ expect(highListener.calledOnce).to.be.false;
+
+ shared.remove(mainListener)
+ .remove(highListener)
+ .remove(lowListener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove emit low-priority item during emit', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself on emit after adding new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.remove(listener1);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself before, still calling new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener1);
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove items before and after current priority', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(listener3, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.add(listener4, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener2)
+ .remove(listener3);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 2);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.update();
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledTwice).to.be.true;
+ expect(listener1.calledTwice).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should destroy on listener', function (done)
+ {
+ const ticker = new Ticker();
+ const listener2 = sinon.spy();
+ const listener = sinon.spy(() =>
+ {
+ ticker.destroy();
+ setTimeout(() =>
+ {
+ expect(listener2.called).to.be.false;
+ expect(listener.calledOnce).to.be.true;
+ done();
+ }, 0);
+ });
+
+ ticker.add(listener);
+ ticker.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ ticker.start();
+ });
+});
diff --git a/test/core/TilingSprite.js b/test/core/TilingSprite.js
index 2e449a7..7694792 100644
--- a/test/core/TilingSprite.js
+++ b/test/core/TilingSprite.js
@@ -24,4 +24,25 @@
expect(bounds.height).to.equal(600);
});
});
+
+ it('checks if tilingSprite contains a point', function ()
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+ const tilingSprite = new PIXI.extras.TilingSprite(texture, 200, 300);
+
+ expect(tilingSprite.containsPoint(new PIXI.Point(1, 1))).to.equal(true);
+ expect(tilingSprite.containsPoint(new PIXI.Point(300, 400))).to.equal(false);
+ });
+
+ it('gets and sets height and width correctly', function ()
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+ const tilingSprite = new PIXI.extras.TilingSprite(texture, 200, 300);
+
+ tilingSprite.width = 400;
+ tilingSprite.height = 600;
+
+ expect(tilingSprite.width).to.equal(400);
+ expect(tilingSprite.height).to.equal(600);
+ });
});
diff --git a/test/core/index.js b/test/core/index.js
index 8530131..58dc30e 100755
--- a/test/core/index.js
+++ b/test/core/index.js
@@ -17,6 +17,7 @@
require('./util');
require('./Plane');
require('./Point');
+require('./Polygon');
require('./ObservablePoint');
require('./Matrix');
require('./Rectangle');
@@ -27,4 +28,5 @@
require('./WebGLRenderer');
require('./Ellipse');
require('./Texture');
+require('./Ticker');
require('./filters');
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 0e7e707..31385b9 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -4,6 +4,16 @@
describe('PIXI.interaction.InteractionManager', function ()
{
+ afterEach(function ()
+ {
+ // if we made a MockPointer for the test, clean it up
+ if (this.pointer)
+ {
+ this.pointer.cleanUp();
+ this.pointer = null;
+ }
+ });
+
describe('event basics', function ()
{
it('should call mousedown handler', function ()
@@ -11,7 +21,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -29,7 +39,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -47,7 +57,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -66,7 +76,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -84,7 +94,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -286,7 +296,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -304,7 +314,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -316,6 +326,29 @@
expect(clickSpy).to.not.have.been.called;
});
+
+ it('should not call handler when mousedown not received', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const clickSpy = sinon.spy();
+ const pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+ graphics.on('click', clickSpy);
+
+ pointer.mouseup(10, 10);
+
+ expect(clickSpy, 'click should not happen on first mouseup').to.not.have.been.called;
+
+ // test again, just because it was a bug that was reported
+ pointer.mouseup(20, 20);
+
+ expect(clickSpy, 'click should not happen on second mouseup').to.not.have.been.called;
+ });
});
describe('onTap', function ()
@@ -325,7 +358,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -343,7 +376,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -359,32 +392,62 @@
describe('overlapping children', function ()
{
- function getScene(callbackEventName)
+ function getScene(callbackEventName, splitParents)
{
const behindChild = new PIXI.Graphics();
const frontChild = new PIXI.Graphics();
const parent = new PIXI.Container();
- const behindChildCallback = sinon.spy();
- const frontChildCallback = sinon.spy();
- const parentCallback = sinon.spy();
+ const behindChildCallback = sinon.spy(function behindSpy() { /* no op*/ });
+ const frontChildCallback = sinon.spy(function frontSpy() { /* no op*/ });
+ const parentCallback = sinon.spy(function parentSpy() { /* no op*/ });
+ let behindParent;
+ let frontParent;
+ let behindParentCallback;
+ let frontParentCallback;
behindChild.beginFill(0xFF);
behindChild.drawRect(0, 0, 50, 50);
behindChild.on(callbackEventName, behindChildCallback);
+ behindChild.name = 'behind';
frontChild.beginFill(0x00FF);
frontChild.drawRect(0, 0, 50, 50);
frontChild.on(callbackEventName, frontChildCallback);
+ frontChild.name = 'front';
- parent.addChild(behindChild, frontChild);
+ if (splitParents)
+ {
+ behindParent = new PIXI.Container();
+ behindParent.name = 'behindParent';
+ frontParent = new PIXI.Container();
+ frontParent.name = 'frontParent';
+ behindParentCallback = sinon.spy(function behindParentSpy() { /* no op*/ });
+ frontParentCallback = sinon.spy(function frontParentSpy() { /* no op*/ });
+ behindParent.on(callbackEventName, behindParentCallback);
+ frontParent.on(callbackEventName, frontParentCallback);
+
+ parent.addChild(behindParent, frontParent);
+ behindParent.addChild(behindChild);
+ frontParent.addChild(frontChild);
+
+ parent.name = 'parent';
+ }
+ else
+ {
+ parent.addChild(behindChild, frontChild);
+ }
parent.on(callbackEventName, parentCallback);
return {
behindChild,
frontChild,
+ behindParent,
+ frontParent,
parent,
behindChildCallback,
frontChildCallback,
+ behindParentCallback,
+ frontParentCallback,
parentCallback,
};
}
@@ -396,7 +459,7 @@
it('should callback front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -414,7 +477,7 @@
it('should callback front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -432,7 +495,7 @@
it('should callback behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -446,6 +509,48 @@
expect(scene.behindChildCallback).to.have.been.calledOnce;
expect(scene.parentCallback).to.not.have.been.called;
});
+
+ it('should callback front child of different non-interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.not.have.been.called;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.not.have.been.called;
+ });
+
+ it('should callback front child of different interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+ scene.behindParent.interactive = true;
+ scene.frontParent.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.not.have.been.called;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.have.been.calledOnce;
+ });
});
describe('when front child is non-interactive', function ()
@@ -453,7 +558,7 @@
it('should not callback when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -470,7 +575,7 @@
it('should callback behind child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -487,7 +592,7 @@
it('should callback behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -507,7 +612,7 @@
it('should callback front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -524,7 +629,7 @@
it('should callback front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -541,7 +646,7 @@
it('should not callback when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -564,7 +669,7 @@
it('should callback parent and front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -583,7 +688,7 @@
it('should callback parent and front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -602,7 +707,7 @@
it('should callback parent and behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -617,6 +722,50 @@
expect(scene.behindChildCallback).to.have.been.calledOnce;
expect(scene.parentCallback).to.have.been.calledOnce;
});
+
+ it('should callback front child of different non-interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+ scene.parent.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.have.been.calledOnce;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.not.have.been.called;
+ });
+
+ it('should callback front child of different interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+ scene.parent.interactive = true;
+ scene.behindParent.interactive = true;
+ scene.frontParent.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.have.been.calledOnce;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.have.been.calledOnce;
+ });
});
describe('when front child is non-interactive', function ()
@@ -624,7 +773,7 @@
it('should callback parent when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -642,7 +791,7 @@
it('should callback parent and behind child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -660,7 +809,7 @@
it('should callback parent and behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -681,7 +830,7 @@
it('should callback parent and front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -699,7 +848,7 @@
it('should callback parent and front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -717,7 +866,7 @@
it('should callback parent when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -733,6 +882,42 @@
});
});
});
+
+ it('Semi-complicated nesting with overlap, should not call behind callback', function ()
+ {
+ const stage = new PIXI.Container();
+ const frontParent = new PIXI.Container();
+ const frontChild = new PIXI.Graphics();
+ const behindParent = new PIXI.Container();
+ const subParent = new PIXI.Container();
+ const behindChild = new PIXI.Graphics();
+ const behindCallback = sinon.spy(function behindSpy() { /* no op*/ });
+ const frontCallback = sinon.spy(function frontSpy() { /* no op*/ });
+
+ behindChild.beginFill(0xFF);
+ behindChild.drawRect(0, 0, 50, 50);
+ subParent.on('click', behindCallback);
+
+ frontChild.beginFill(0x00FF);
+ frontChild.drawRect(0, 0, 50, 50);
+ frontParent.on('click', frontCallback);
+ const pointer = this.pointer = new MockPointer(stage);
+
+ behindParent.x = 25;
+ subParent.interactive = true;
+ frontParent.interactive = true;
+
+ behindParent.addChild(subParent);
+ subParent.addChild(behindChild);
+ stage.addChild(behindParent);
+ frontParent.addChild(frontChild);
+ stage.addChild(frontParent);
+
+ pointer.click(40, 10);
+
+ expect(behindCallback).to.not.have.been.called;
+ expect(frontCallback).to.have.been.calledOnce;
+ });
});
describe('cursor changes', function ()
@@ -741,7 +926,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -759,7 +944,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -778,7 +963,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -797,7 +982,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -818,7 +1003,7 @@
const graphics = new PIXI.Graphics();
const overSpy = sinon.spy();
const defaultSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -840,7 +1025,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const defaultSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -859,7 +1044,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -881,7 +1066,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -932,7 +1117,7 @@
it('should stop hitTesting after first hit', function ()
{
const scene = getScene();
- const pointer = new MockPointer(scene.stage);
+ const pointer = this.pointer = new MockPointer(scene.stage);
const frontHitTest = sinon.spy(scene.frontChild, 'containsPoint');
const middleHitTest = sinon.spy(scene.middleChild, 'containsPoint');
const behindHitTest = sinon.spy(scene.behindChild, 'containsPoint');
@@ -954,7 +1139,7 @@
it('should stop hitTesting after first hit', function ()
{
const scene = getScene();
- const pointer = new MockPointer(scene.stage);
+ const pointer = this.pointer = new MockPointer(scene.stage);
const frontHitTest = sinon.spy(scene.frontChild, 'containsPoint');
const middleHitTest = sinon.spy(scene.middleChild, 'containsPoint');
const behindHitTest = sinon.spy(scene.behindChild, 'containsPoint');
@@ -971,4 +1156,127 @@
});
});
});
+
+ describe('pointer handling', function ()
+ {
+ it('pointer event from mouse should use single mouse data', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage, 100, 100, true);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.mousemove(20, 10, true);
+
+ expect(pointer.interaction.mouse.global.x).to.equal(20);
+ expect(pointer.interaction.mouse.global.y).to.equal(10);
+ });
+ });
+
+ describe('data cleanup', function ()
+ {
+ it('touchleave after touchout should not orphan data', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.touchstart(10, 10, 42);
+ expect(pointer.interaction.activeInteractionData[42]).to.exist;
+ pointer.touchend(10, 10, 42);
+ expect(pointer.interaction.activeInteractionData[42]).to.be.undefined;
+ pointer.touchleave(10, 10, 42);
+ expect(pointer.interaction.activeInteractionData[42]).to.be.undefined;
+ });
+ });
+
+ describe('hitTest()', function ()
+ {
+ it('should return hit', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(10, 10));
+
+ expect(hit).to.equal(graphics);
+ });
+
+ it('should return null if not hit', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(60, 60));
+
+ expect(hit).to.be.null;
+ });
+
+ it('should return top thing that was hit', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const behind = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(behind);
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+ behind.beginFill(0xFFFFFF);
+ behind.drawRect(0, 0, 50, 50);
+ behind.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(10, 10));
+
+ expect(hit).to.equal(graphics);
+ });
+
+ it('should return hit when passing in root', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const behind = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(behind);
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+ behind.beginFill(0xFFFFFF);
+ behind.drawRect(0, 0, 50, 50);
+ behind.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(10, 10), behind);
+
+ expect(hit).to.equal(behind);
+ });
+ });
});
diff --git a/test/interaction/MockPointer.js b/test/interaction/MockPointer.js
index 67878af..c9c6228 100644
--- a/test/interaction/MockPointer.js
+++ b/test/interaction/MockPointer.js
@@ -11,13 +11,43 @@
* @param {PIXI.Container} stage - The root of the scene tree
* @param {number} [width=100] - Width of the renderer
* @param {number} [height=100] - Height of the renderer
+ * @param {boolean} [ensurePointerEvents=false] - If we should make sure that PointerEvents are 'supported'
*/
- constructor(stage, width, height)
+ constructor(stage, width, height, ensurePointerEvents)
{
+ // fake PointerEvent existing
+ if (ensurePointerEvents && !window.PointerEvent)
+ {
+ window.PointerEvent = class PointerEvent extends MouseEvent
+ {
+ //eslint-disable-next-line
+ constructor(type, opts)
+ {
+ super(type, opts);
+ this.pointerType = opts.pointerType;
+ }
+ };
+ this.createdPointerEvent = true;
+ }
+
this.stage = stage;
this.renderer = new PIXI.CanvasRenderer(width || 100, height || 100);
this.renderer.sayHello = () => { /* empty */ };
this.interaction = this.renderer.plugins.interaction;
+ this.interaction.supportsTouchEvents = true;
+ PIXI.ticker.shared.remove(this.interaction.update, this.interaction);
+ }
+
+ /**
+ * Cleans up after tests
+ */
+ cleanup()
+ {
+ if (this.createdPointerEvent)
+ {
+ delete window.PointerEvent;
+ }
+ this.renderer.destroy();
}
/**
@@ -45,14 +75,29 @@
/**
* @param {number} x - pointer x position
* @param {number} y - pointer y position
+ * @param {boolean} [asPointer] - if it should be a PointerEvent from a mouse
*/
- mousemove(x, y)
+ mousemove(x, y, asPointer)
{
- const mouseEvent = new MouseEvent('mousemove', {
- clientX: x,
- clientY: y,
- preventDefault: sinon.stub(),
- });
+ let mouseEvent;
+
+ if (asPointer)
+ {
+ mouseEvent = new PointerEvent('pointermove', {
+ pointerType: 'mouse',
+ clientX: x,
+ clientY: y,
+ preventDefault: sinon.stub(),
+ });
+ }
+ else
+ {
+ mouseEvent = new MouseEvent('mousemove', {
+ clientX: x,
+ clientY: y,
+ preventDefault: sinon.stub(),
+ });
+ }
this.setPosition(x, y);
this.render();
@@ -97,9 +142,15 @@
*/
mousedown(x, y)
{
+ const mouseEvent = new MouseEvent('mousedown', {
+ clientX: x,
+ clientY: y,
+ preventDefault: sinon.stub(),
+ });
+
this.setPosition(x, y);
this.render();
- this.interaction.onMouseDown({ clientX: 0, clientY: 0, preventDefault: sinon.stub() });
+ this.interaction.onPointerDown(mouseEvent);
}
/**
@@ -108,47 +159,83 @@
*/
mouseup(x, y)
{
- this.setPosition(x, y);
- this.render();
- this.interaction.onMouseUp({ clientX: 0, clientY: 0, preventDefault: sinon.stub() });
- }
-
- /**
- * @param {number} x - pointer x position
- * @param {number} y - pointer y position
- */
- tap(x, y)
- {
- this.touchstart(x, y);
- this.touchend(x, y);
- }
-
- /**
- * @param {number} x - pointer x position
- * @param {number} y - pointer y position
- */
- touchstart(x, y)
- {
- this.setPosition(x, y);
- this.render();
- this.interaction.onTouchStart({
+ const mouseEvent = new MouseEvent('mouseup', {
+ clientX: x,
+ clientY: y,
preventDefault: sinon.stub(),
- changedTouches: [new Touch({ identifier: 0, target: this.renderer.view })],
});
+
+ this.setPosition(x, y);
+ this.render();
+ this.interaction.onPointerUp(mouseEvent);
}
/**
* @param {number} x - pointer x position
* @param {number} y - pointer y position
+ * @param {number} [identifier] - pointer id
*/
- touchend(x, y)
+ tap(x, y, identifier)
{
+ this.touchstart(x, y, identifier);
+ this.touchend(x, y, identifier);
+ }
+
+ /**
+ * @param {number} x - pointer x position
+ * @param {number} y - pointer y position
+ * @param {number} [identifier] - pointer id
+ */
+ touchstart(x, y, identifier)
+ {
+ const touchEvent = new TouchEvent('touchstart', {
+ preventDefault: sinon.stub(),
+ changedTouches: [
+ new Touch({ identifier: identifier || 0, target: this.renderer.view }),
+ ],
+ });
+
this.setPosition(x, y);
this.render();
- this.interaction.onTouchEnd({
+ this.interaction.onPointerDown(touchEvent);
+ }
+
+ /**
+ * @param {number} x - pointer x position
+ * @param {number} y - pointer y position
+ * @param {number} [identifier] - pointer id
+ */
+ touchend(x, y, identifier)
+ {
+ const touchEvent = new TouchEvent('touchend', {
preventDefault: sinon.stub(),
- changedTouches: [new Touch({ identifier: 0, target: this.renderer.view })],
+ changedTouches: [
+ new Touch({ identifier: identifier || 0, target: this.renderer.view }),
+ ],
});
+
+ this.setPosition(x, y);
+ this.render();
+ this.interaction.onPointerUp(touchEvent);
+ }
+
+ /**
+ * @param {number} x - pointer x position
+ * @param {number} y - pointer y position
+ * @param {number} [identifier] - pointer id
+ */
+ touchleave(x, y, identifier)
+ {
+ const touchEvent = new TouchEvent('touchleave', {
+ preventDefault: sinon.stub(),
+ changedTouches: [
+ new Touch({ identifier: identifier || 0, target: this.renderer.view }),
+ ],
+ });
+
+ this.setPosition(x, y);
+ this.render();
+ this.interaction.onPointerOut(touchEvent);
}
}
diff --git a/test/loaders/spritesheetParser.js b/test/loaders/spritesheetParser.js
index 79f8c15..4d54805 100644
--- a/test/loaders/spritesheetParser.js
+++ b/test/loaders/spritesheetParser.js
@@ -60,11 +60,46 @@
.that.is.an.instanceof(PIXI.Texture);
});
+ it('should build the image url', function ()
+ {
+ function getResourcePath(url, image)
+ {
+ return PIXI.loaders.getResourcePath({
+ url,
+ data: { meta: { image } },
+ });
+ }
+
+ let result = getResourcePath('http://some.com/spritesheet.json', 'img.png');
+
+ expect(result).to.be.equals('http://some.com/img.png');
+
+ result = getResourcePath('http://some.com/some/dir/spritesheet.json', 'img.png');
+ expect(result).to.be.equals('http://some.com/some/dir/img.png');
+
+ result = getResourcePath('http://some.com/some/dir/spritesheet.json', './img.png');
+ expect(result).to.be.equals('http://some.com/some/dir/img.png');
+
+ result = getResourcePath('http://some.com/some/dir/spritesheet.json', '../img.png');
+ expect(result).to.be.equals('http://some.com/some/img.png');
+
+ result = getResourcePath('/spritesheet.json', 'img.png');
+ expect(result).to.be.equals('/img.png');
+
+ result = getResourcePath('/some/dir/spritesheet.json', 'img.png');
+ expect(result).to.be.equals('/some/dir/img.png');
+
+ result = getResourcePath('/some/dir/spritesheet.json', './img.png');
+ expect(result).to.be.equals('/some/dir/img.png');
+
+ result = getResourcePath('/some/dir/spritesheet.json', '../img.png');
+ expect(result).to.be.equals('/some/img.png');
+ });
+
// TODO: Test that rectangles are created correctly.
// TODO: Test that bathc processing works correctly.
// TODO: Test that resolution processing works correctly.
// TODO: Test that metadata is honored.
- // TODO: Test data-url code paths.
});
function createMockResource(type, data)
diff --git a/.travis.yml b/.travis.yml
index 3df8b22..14de334 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -110,3 +110,43 @@
on:
all_branches: true
condition: $TRAVIS_TAG
+ # Deploy config for latest release
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: dist
+ upload-dir: "release"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: docs
+ upload-dir: "release/docs"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
+ - provider: s3
+ access_key_id: $S3_ACCESS_KEY_ID
+ secret_access_key: $S3_SECRET_ACCESS_KEY
+ bucket: "pixi.js"
+ skip_cleanup: true
+ acl: public_read
+ region: eu-west-1
+ cache_control: "max-age=1209600"
+ local_dir: coverage
+ upload-dir: "release/coverage"
+ on:
+ all_branches: true
+ condition: $TRAVIS_TAG
\ No newline at end of file
diff --git a/README.md b/README.md
index d26fadd..3b85f85 100644
--- a/README.md
+++ b/README.md
@@ -36,22 +36,14 @@
- Wiki: Other misc tutorials and resources are [on the Wiki](https://github.com/pixijs/pixi.js/wiki/Resources).
### Community ###
-- Forums: Check out the [forum] (http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow] (http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
+- Forums: Check out the [forum](http://www.html5gamedevs.com/forum/15-pixijs/) and [Stackoverflow](http://stackoverflow.com/search?q=pixi.js), both friendly places to ask your pixi questions.
- Inspiration: Check out the [gallery](http://www.pixijs.com/gallery) to see some of the amazing things people have created!
- Chat: You can join us on [Gitter](https://gitter.im/pixijs/pixi.js) To chat about Pixi. We also now have a Slack channel. If you would like to join it please Send me an email (mat@goodboydigital.com) and I will invite you in.
### Setup ###
-It's easy to get started with Pixi.js! Simply grab the pre-built versions from here:
-
-Release Branch - Nice and stable Pixi.js
-- Unminified: [http://pixijs.download/release/pixi.js]
-- Minified: [http://pixijs.download/release/pixi.min.js]
-
-Develop Branch - The bleeding edge version of Pixi.js
-- Unminified: [http://pixijs.download/dev/pixi.js]
-- Minified: [http://pixijs.download/dev/pixi.min.js]
+It's easy to get started with Pixi.js! Simply download a [prebuilt build](https://github.com/pixijs/pixi.js/wiki/FAQs#where-can-i-get-a-build)!
Alternatively, Pixi.js can be installed with [Bower](https://bower.io/#getting-started), [npm](https://docs.npmjs.com/getting-started/what-is-npm) or simply using a content delivery network (CDN) URL to embed Pixi.js directly on your HTML page.
@@ -70,10 +62,10 @@
#### CDN Install (via cdnjs)
```html
-
+
```
-_Note: `4.2.2` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
+_Note: `4.4.3` can be replaced by any [released](https://github.com/pixijs/pixi.js/releases) version._
### Demos ###
@@ -130,7 +122,7 @@
// and the root stage PIXI.Container.
var app = new PIXI.Application();
-// The application will create a canvas element for you that you
+// The application will create a canvas element for you that you
// can then insert into the DOM.
document.body.appendChild(app.view);
@@ -150,7 +142,7 @@
// Add the bunny to the scene we are building.
app.stage.addChild(bunny);
-
+
// Listen for frame updates
app.ticker.add(function() {
// each frame we spin the bunny around a bit
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 41b668c..0000000
--- a/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "pixi.js",
- "main": "dist/pixi.min.js",
- "ignore": [
- "**/.*",
- "docs",
- "node_modules",
- "bower_components",
- "test",
- "scripts",
- "bower.json",
- "inch.json"
- ],
- "dependencies": {
- },
- "devDependencies": {
- }
-}
diff --git a/package.json b/package.json
index d35cbb2..308469f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pixi.js",
- "version": "4.3.5",
+ "version": "4.4.4",
"description": "Pixi.js is a fast lightweight 2D library that works across all devices.",
"author": "Mat Groves",
"contributors": [
@@ -40,11 +40,11 @@
"lib": "babel src --out-dir lib -s",
"predocs": "rimraf docs/**",
"docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md",
- "publish:patch": "npm version patch --no-git-tag-version && npm publish",
- "publish:minor": "npm version minor --no-git-tag-version && npm publish",
- "publish:major": "npm version major --no-git-tag-version && npm publish",
+ "publish:patch": "npm version patch && npm publish",
+ "publish:minor": "npm version minor && npm publish",
+ "publish:major": "npm version major && npm publish",
"postversion": "npm run clean && npm run build && npm run lib && npm test",
- "postpublish": "node scripts/release.js"
+ "postpublish": "git push && git push --tags"
},
"files": [
"dist/",
@@ -72,7 +72,6 @@
"electron": "^1.4.15",
"eslint": "^3.5.0",
"floss": "^2.0.1",
- "gh-pages": "^0.11.0",
"jaguarjs-jsdoc": "^1.0.1",
"js-md5": "^0.4.1",
"jsdoc": "^3.4.2",
diff --git a/scripts/jsdoc.conf.json b/scripts/jsdoc.conf.json
index 553e61c..3f52180 100644
--- a/scripts/jsdoc.conf.json
+++ b/scripts/jsdoc.conf.json
@@ -43,7 +43,7 @@
},
"markdown" : {
"parser" : "gfm",
- "hardwrap" : true
+ "hardwrap" : false
},
"opts": {
"encoding" : "utf8",
diff --git a/scripts/release.js b/scripts/release.js
deleted file mode 100644
index 156620c..0000000
--- a/scripts/release.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-// Publish script to push releases of the bin files
-// the normally are gitignored
-const ghpages = require('gh-pages');
-const path = require('path');
-const packageInfo = require(path.join(__dirname, '..', 'package.json'));
-
-const options = {
- src: [
- 'dist/**/*',
- 'lib/**/*',
- 'src/**/*',
- 'scripts/*',
- 'scripts/renders/*',
- 'test/**/*',
- '*.json',
- '*.md',
- 'LICENSE',
- '.eslintrc',
- '.editorconfig',
- '.travis.yml',
- '.babelrc',
- ],
- dotfiles: true,
- branch: 'release',
- message: packageInfo.version,
- logger: console.log.bind(console),
-};
-
-ghpages.publish(process.cwd(), options, (err) =>
-{
- if (err)
- {
- console.log(err);
- process.exit(1);
-
- return;
- }
-
- process.exit(0);
-});
diff --git a/src/accessibility/AccessibilityManager.js b/src/accessibility/AccessibilityManager.js
index f16bcb1..220427a 100644
--- a/src/accessibility/AccessibilityManager.js
+++ b/src/accessibility/AccessibilityManager.js
@@ -21,7 +21,7 @@
const DIV_HOOK_ZINDEX = 2;
/**
- * The Accessibility manager reacreates the ability to tab and and have content read by screen
+ * The Accessibility manager recreates the ability to tab and and have content read by screen
* readers. This is very important as it can possibly help people with disabilities access pixi
* content.
*
diff --git a/src/accessibility/index.js b/src/accessibility/index.js
index 568cfb1..0ae108f 100644
--- a/src/accessibility/index.js
+++ b/src/accessibility/index.js
@@ -1,4 +1,9 @@
/**
+ * This namespace contains a renderer plugin for interaction accessibility for end-users
+ * with physical impairments which require screen-renders, keyboard navigation, etc.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.accessibility
*/
export { default as accessibleTarget } from './accessibleTarget';
diff --git a/src/core/Application.js b/src/core/Application.js
index 5340578..2fcc729 100644
--- a/src/core/Application.js
+++ b/src/core/Application.js
@@ -1,6 +1,8 @@
import { autoDetectRenderer } from './autoDetectRenderer';
import Container from './display/Container';
import { shared, Ticker } from './ticker';
+import settings from './settings';
+import { UPDATE_PRIORITY } from './const';
/**
* Convenience class to create a new PIXI application.
@@ -22,28 +24,52 @@
*/
export default class Application
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experience unexplained flickering try setting this to true.
- * @param {boolean} [useSharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker.
+ * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader.
*/
- constructor(width, height, options, noWebGL, useSharedTicker = false)
+ constructor(options, arg2, arg3, arg4, arg5)
{
+ // Support for constructor(width, height, options, noWebGL, useSharedTicker)
+ if (typeof options === 'number')
+ {
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ forceCanvas: !!arg4,
+ sharedTicker: !!arg5,
+ }, arg3);
+ }
+
+ /**
+ * The default options, so we mixin functionality later.
+ * @member {object}
+ * @protected
+ */
+ this._options = options = Object.assign({
+ sharedTicker: false,
+ forceCanvas: false,
+ sharedLoader: false,
+ }, options);
+
/**
* WebGL renderer if available, otherwise CanvasRenderer
* @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer}
*/
- this.renderer = autoDetectRenderer(width, height, options, noWebGL);
+ this.renderer = autoDetectRenderer(options);
/**
* The root display container that's rendered.
@@ -63,7 +89,7 @@
* @member {PIXI.ticker.Ticker}
* @default PIXI.ticker.shared
*/
- this.ticker = useSharedTicker ? shared : new Ticker();
+ this.ticker = options.sharedTicker ? shared : new Ticker();
// Start the rendering
this.start();
@@ -78,7 +104,7 @@
this._ticker = ticker;
if (ticker)
{
- ticker.add(this.render, this);
+ ticker.add(this.render, this, UPDATE_PRIORITY.LOW);
}
}
get ticker() // eslint-disable-line require-jsdoc
@@ -136,13 +162,18 @@
*/
destroy(removeView)
{
- this.stop();
+ const oldTicker = this._ticker;
+
this.ticker = null;
+ oldTicker.destroy();
+
this.stage.destroy();
this.stage = null;
this.renderer.destroy(removeView);
this.renderer = null;
+
+ this._options = null;
}
}
diff --git a/src/core/autoDetectRenderer.js b/src/core/autoDetectRenderer.js
index 8960425..9ec0364 100644
--- a/src/core/autoDetectRenderer.js
+++ b/src/core/autoDetectRenderer.js
@@ -2,6 +2,7 @@
import CanvasRenderer from './renderers/canvas/CanvasRenderer';
import WebGLRenderer from './renderers/webgl/WebGLRenderer';
+// eslint-disable-next-line valid-jsdoc
/**
* This helper function will automatically detect which renderer you should be using.
* WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by
@@ -9,24 +10,32 @@
*
* @memberof PIXI
* @function autoDetectRenderer
- * @param {number} [width=800] - the width of the renderers view
- * @param {number} [height=600] - the height of the renderers view
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the renderers view
+ * @param {number} [options.height=600] - the height of the renderers view
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
* @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you
* need to call toDataUrl on the webgl context
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2
- * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present
+ * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present
* @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer
*/
-export function autoDetectRenderer(width = 800, height = 600, options, noWebGL)
+export function autoDetectRenderer(options, arg1, arg2, arg3)
{
- if (!noWebGL && utils.isWebGLSupported())
+ // Backward-compatible support for noWebGL option
+ let forceCanvas = options && options.forceCanvas;
+
+ if (arg3 !== undefined)
{
- return new WebGLRenderer(width, height, options);
+ forceCanvas = arg3;
}
- return new CanvasRenderer(width, height, options);
+ if (!forceCanvas && utils.isWebGLSupported())
+ {
+ return new WebGLRenderer(options, arg1, arg2);
+ }
+
+ return new CanvasRenderer(options, arg1, arg2);
}
diff --git a/src/core/const.js b/src/core/const.js
index b9e99ae..2c68dee 100644
--- a/src/core/const.js
+++ b/src/core/const.js
@@ -341,3 +341,27 @@
LINEAR_VERTICAL: 0,
LINEAR_HORIZONTAL: 1,
};
+
+/**
+ * Represents the update priorities used by internal PIXI classes when registered with
+ * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower
+ * priority items, such as render, should go later.
+ *
+ * @static
+ * @constant
+ * @name UPDATE_PRIORITY
+ * @memberof PIXI
+ * @type {object}
+ * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager}
+ * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite}
+ * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}.
+ * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering.
+ * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility.
+ */
+export const UPDATE_PRIORITY = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50,
+};
diff --git a/src/core/display/DisplayObject.js b/src/core/display/DisplayObject.js
index 4e6c77d..decb42a 100644
--- a/src/core/display/DisplayObject.js
+++ b/src/core/display/DisplayObject.js
@@ -13,7 +13,6 @@
*
* @class
* @extends EventEmitter
- * @mixes PIXI.interaction.interactiveTarget
* @memberof PIXI
*/
export default class DisplayObject extends EventEmitter
@@ -113,6 +112,29 @@
* @private
*/
this._mask = null;
+
+ /**
+ * If the object has been destroyed via destroy(). If true, it should not be used.
+ *
+ * @member {boolean}
+ * @private
+ * @readonly
+ */
+ this._destroyed = false;
+
+ /**
+ * Fired when this DisplayObject is added to a Container.
+ *
+ * @event PIXI.DisplayObject#added
+ * @param {PIXI.Container} container - The container added to.
+ */
+
+ /**
+ * Fired when this DisplayObject is removed from a Container.
+ *
+ * @event PIXI.DisplayObject#removed
+ * @param {PIXI.Container} container - The container removed from.
+ */
}
/**
@@ -403,6 +425,8 @@
this.interactive = false;
this.interactiveChildren = false;
+
+ this._destroyed = true;
}
/**
diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js
index aafdfe2..f787c4a 100644
--- a/src/core/graphics/Graphics.js
+++ b/src/core/graphics/Graphics.js
@@ -792,8 +792,8 @@
sprite.worldAlpha = this.worldAlpha * sprite.alpha;
sprite.blendMode = this.blendMode;
- sprite.texture._frame.width = rect.width;
- sprite.texture._frame.height = rect.height;
+ sprite._texture._frame.width = rect.width;
+ sprite._texture._frame.height = rect.height;
sprite.transform.worldTransform = this.transform.worldTransform;
diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js
index a24c775..b9f192d 100644
--- a/src/core/renderers/SystemRenderer.js
+++ b/src/core/renderers/SystemRenderer.js
@@ -19,11 +19,12 @@
*/
export default class SystemRenderer extends EventEmitter
{
+ // eslint-disable-next-line valid-jsdoc
/**
* @param {string} system - The name of the system this renderer is for.
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -37,27 +38,31 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(system, screenWidth, screenHeight, options)
+ constructor(system, options, arg2, arg3)
{
super();
sayHello(system);
- // prepare options
- if (options)
+ // Support for constructor(system, screenWidth, screenHeight, options)
+ if (typeof options === 'number')
{
- for (const i in settings.RENDER_OPTIONS)
- {
- if (typeof options[i] === 'undefined')
- {
- options[i] = settings.RENDER_OPTIONS[i];
- }
- }
+ options = Object.assign({
+ width: options,
+ height: arg2 || settings.RENDER_OPTIONS.height,
+ }, arg3);
}
- else
- {
- options = settings.RENDER_OPTIONS;
- }
+
+ // Add the default render options
+ options = Object.assign({}, settings.RENDER_OPTIONS, options);
+
+ /**
+ * The supplied constructor options.
+ *
+ * @member {Object}
+ * @readOnly
+ */
+ this.options = options;
/**
* The type of the renderer.
@@ -75,7 +80,7 @@
*
* @member {PIXI.Rectangle}
*/
- this.screen = new Rectangle(0, 0, screenWidth || 800, screenHeight || 600);
+ this.screen = new Rectangle(0, 0, options.width, options.height);
/**
* The canvas element that everything is drawn to
@@ -279,6 +284,8 @@
this.blendModes = null;
+ this.options = null;
+
this.preserveDrawingBuffer = false;
this.clearBeforeRender = false;
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index e84e49c..691caf0 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -17,10 +17,11 @@
*/
export default class CanvasRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -34,9 +35,9 @@
* @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering,
* stopping pixel interpolation.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('Canvas', screenWidth, screenHeight, options);
+ super('Canvas', options, arg2, arg3);
this.type = RENDERER_TYPE.CANVAS;
@@ -96,7 +97,19 @@
this.context = null;
this.renderingToScreen = false;
- this.resize(screenWidth, screenHeight);
+ this.resize(this.options.width, this.options.height);
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.CanvasRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.CanvasRenderer#prerender
+ */
}
/**
@@ -299,4 +312,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.CanvasRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.CanvasRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(CanvasRenderer);
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e1cf7cd..f6fe123 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -31,11 +31,12 @@
*/
export default class WebGLRenderer extends SystemRenderer
{
+ // eslint-disable-next-line valid-jsdoc
/**
*
- * @param {number} [screenWidth=800] - the width of the screen
- * @param {number} [screenHeight=600] - the height of the screen
* @param {object} [options] - The optional renderer parameters
+ * @param {number} [options.width=800] - the width of the screen
+ * @param {number} [options.height=600] - the height of the screen
* @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
* @param {boolean} [options.transparent=false] - If the render view is transparent, default false
* @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
@@ -55,9 +56,9 @@
* @param {boolean} [options.legacy=false] - If true Pixi will aim to ensure compatibility
* with older / less advanced devices. If you experiance unexplained flickering try setting this to true.
*/
- constructor(screenWidth, screenHeight, options = {})
+ constructor(options, arg2, arg3)
{
- super('WebGL', screenWidth, screenHeight, options);
+ super('WebGL', options, arg2, arg3);
/**
* The type of this renderer as a standardised const
@@ -89,12 +90,6 @@
};
- /**
- * The options passed in to create a new webgl context.
- *
- * @member {object}
- * @private
- */
this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
this.globalUniforms = new UniformGroup({
@@ -117,6 +112,13 @@
this.initPlugins();
+
+ /**
+ * The options passed in to create a new webgl context.
+ *
+ * @member {object}
+ * @private
+ */
if(options.context)
{
this.context.initFromContext(options.context);
@@ -169,6 +171,25 @@
}
return this;
+
+ /**
+ * Fired after rendering finishes.
+ *
+ * @event PIXI.WebGLRenderer#postrender
+ */
+
+ /**
+ * Fired before rendering starts.
+ *
+ * @event PIXI.WebGLRenderer#prerender
+ */
+
+ /**
+ * Fired when the WebGL context is set.
+ *
+ * @event PIXI.WebGLRenderer#context
+ * @param {WebGLRenderingContext} gl - WebGL context.
+ */
}
/**
@@ -295,4 +316,25 @@
}
}
+/**
+ * Collection of installed plugins. These are included by default in PIXI, but can be excluded
+ * by creating a custom build. Consult the README for more information about creating custom
+ * builds and excluding plugins.
+ * @name PIXI.WebGLRenderer#plugins
+ * @type {object}
+ * @readonly
+ * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
+ * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
+ * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
+ * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
+ */
+
+/**
+ * Adds a plugin to the renderer.
+ *
+ * @method PIXI.WebGLRenderer#registerPlugin
+ * @param {string} pluginName - The name of the plugin.
+ * @param {Function} ctor - The constructor function or class for the plugin.
+ */
+
pluginTarget.mixin(WebGLRenderer);
diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js
index 4eb6128..fa3d883 100644
--- a/src/core/renderers/webgl/filters/Filter.js
+++ b/src/core/renderers/webgl/filters/Filter.js
@@ -47,6 +47,14 @@
* @member {boolean}
*/
this.enabled = true;
+
+ /**
+ * If enabled, pixi will fit the filter area into boundaries for better performance.
+ * Switch it off if it does not work for specific shader.
+ *
+ * @member {boolean}
+ */
+ this.autoFit = true;
}
/**
diff --git a/src/core/renderers/webgl/systems/ContextSystem.js b/src/core/renderers/webgl/systems/ContextSystem.js
index ff958c7..8df85ea 100644
--- a/src/core/renderers/webgl/systems/ContextSystem.js
+++ b/src/core/renderers/webgl/systems/ContextSystem.js
@@ -75,7 +75,8 @@
*/
createContext(canvas, options)
{
- var gl = canvas.getContext('webgl', options) ||
+ var gl = //canvas.getContext('webgl2', options) ||
+ canvas.getContext('webgl', options) ||
canvas.getContext('experimental-webgl', options);
if (!gl)
diff --git a/src/core/renderers/webgl/systems/FilterSystem.js b/src/core/renderers/webgl/systems/FilterSystem.js
index f47335d..37e28d2 100644
--- a/src/core/renderers/webgl/systems/FilterSystem.js
+++ b/src/core/renderers/webgl/systems/FilterSystem.js
@@ -111,7 +111,7 @@
// TODO we should fit the rect around the transform..
}
- else
+ else if (filters[0].autoFit)
{
sourceFrame.fit(filterData.stack[0].destinationFrame);
}
diff --git a/src/core/renderers/webgl/systems/shader/shader/mapType.js b/src/core/renderers/webgl/systems/shader/shader/mapType.js
index 581dace..917538a 100644
--- a/src/core/renderers/webgl/systems/shader/shader/mapType.js
+++ b/src/core/renderers/webgl/systems/shader/shader/mapType.js
@@ -15,7 +15,7 @@
}
}
- return GL_TABLE[type];
+ return GL_TABLE[type];
};
var GL_TABLE = null;
diff --git a/src/core/settings.js b/src/core/settings.js
index 18c5877..38ef45c 100644
--- a/src/core/settings.js
+++ b/src/core/settings.js
@@ -2,6 +2,15 @@
import canUploadSameBuffer from './utils/canUploadSameBuffer';
/**
+ * User's customizable globals for overriding the default PIXI settings, such
+ * as a renderer's default resolution, framerate, float percision, etc.
+ * @example
+ * // Use the native window resolution as the default resolution
+ * // will support high-density displays when rendering
+ * PIXI.settings.RESOLUTION = window.devicePixelRatio.
+ *
+ * // Disable interpolation when scaling, will make texture be pixelated
+ * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
* @namespace PIXI.settings
*/
export default {
@@ -101,6 +110,9 @@
* @property {boolean} clearBeforeRender=true
* @property {boolean} preserveDrawingBuffer=false
* @property {boolean} roundPixels=false
+ * @property {number} width=800
+ * @property {number} height=600
+ * @property {boolean} legacy=false
*/
RENDER_OPTIONS: {
view: null,
@@ -112,6 +124,9 @@
clearBeforeRender: true,
preserveDrawingBuffer: false,
roundPixels: false,
+ width: 800,
+ height: 600,
+ legacy: false,
},
/**
diff --git a/src/core/shader/Program.js b/src/core/shader/Program.js
index c0b538b..07b4398 100644
--- a/src/core/shader/Program.js
+++ b/src/core/shader/Program.js
@@ -1,6 +1,6 @@
import extractUniformsFromSrc from './extractUniformsFromSrc';
import generateUniformsSync from './generateUniformsSync';
-import glCore from 'pixi-gl-core';
+import shaderUtils from '../renderers/webgl/systems/shader/shader';
import { ProgramCache } from '../utils';
import getTestContext from '../utils/getTestContext';
@@ -64,14 +64,17 @@
}
else
{
- vertexSrc = glCore.shader.setPrecision(vertexSrc, 'mediump');
- fragmentSrc = glCore.shader.setPrecision(fragmentSrc, 'mediump');
+ vertexSrc = shaderUtils.setPrecision(vertexSrc, 'mediump');
+ fragmentSrc = shaderUtils.setPrecision(fragmentSrc, 'mediump');
- const program = glCore.shader.compileProgram(gl, vertexSrc, fragmentSrc);
+ const program = shaderUtils.compileProgram(gl, vertexSrc, fragmentSrc);
+ console.log("<<<<<<>>><<");
this.attributeData = this.getAttributeData(program, gl);
this.uniformData = this.getUniformData(program, gl);
+ console.log(this.uniformData);
+
//gl.deleteProgram(program);
}
}
@@ -95,13 +98,13 @@
for (let i = 0; i < totalAttributes; i++)
{
const attribData = gl.getActiveAttrib(program, i);
- const type = glCore.shader.mapType(gl, attribData.type);
+ const type = shaderUtils.mapType(gl, attribData.type);
/*eslint-disable */
const data = {
type: type,
name: attribData.name,
- size: glCore.shader.mapSize(type),
+ size: shaderUtils.mapSize(type),
location: 0,
};
/*eslint-enable */
@@ -137,13 +140,14 @@
// TODO expose this as a prop?
// const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
- const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
+ //const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$');
for (let i = 0; i < totalUniforms; i++)
{
const uniformData = gl.getActiveUniform(program, i);
const name = uniformData.name.replace(/\[.*?\]/, '');
- const type = glCore.shader.mapType(gl, uniformData.type);
+ const type = shaderUtils.mapType(gl, uniformData.type);
+ console.log('mapping ' + uniformData.type + ' to ' + type);
// if (!name.match(maskRegex))
{
@@ -151,7 +155,7 @@
uniforms[name] = {
type: type,
size: uniformData.size,
- value: glCore.shader.defaultValue(type, uniformData.size),
+ value: shaderUtils.defaultValue(type, uniformData.size),
};
/*eslint-enable */
}
diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js
index e387e99..b57d095 100644
--- a/src/core/sprites/Sprite.js
+++ b/src/core/sprites/Sprite.js
@@ -147,12 +147,12 @@
// so if _width is 0 then width was not set..
if (this._width)
{
- this.scale.x = sign(this.scale.x) * this._width / this.texture.orig.width;
+ this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width;
}
if (this._height)
{
- this.scale.y = sign(this.scale.y) * this._height / this.texture.orig.height;
+ this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height;
}
}
diff --git a/src/core/sprites/canvas/CanvasTinter.js b/src/core/sprites/canvas/CanvasTinter.js
index 27e5e0c..fd9de5d 100644
--- a/src/core/sprites/canvas/CanvasTinter.js
+++ b/src/core/sprites/canvas/CanvasTinter.js
@@ -18,7 +18,7 @@
*/
getTintedTexture: (sprite, color) =>
{
- const texture = sprite.texture;
+ const texture = sprite._texture;
color = CanvasTinter.roundColor(color);
diff --git a/src/core/text/Text.js b/src/core/text/Text.js
index 5a4edda..8b9b797 100644
--- a/src/core/text/Text.js
+++ b/src/core/text/Text.js
@@ -344,6 +344,7 @@
const texture = this._texture;
const style = this._style;
+ const padding = style.trim ? 0 : style.padding;
texture.baseTexture.valid = true;
texture.baseTexture.resolution = this.resolution;
@@ -353,11 +354,11 @@
texture.trim.width = texture._frame.width = this.canvas.width / this.resolution;
texture.trim.height = texture._frame.height = this.canvas.height / this.resolution;
- texture.trim.x = -style.padding;
- texture.trim.y = -style.padding;
+ texture.trim.x = -padding;
+ texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (style.padding * 2);
- texture.orig.height = texture._frame.height - (style.padding * 2);
+ texture.orig.width = texture._frame.width - (padding * 2);
+ texture.orig.height = texture._frame.height - (padding * 2);
// call sprite onTextureUpdate to update scale if _width or _height were set
this._onTextureUpdate();
diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js
index 853da3d..8a9c34b 100644
--- a/src/core/textures/BaseTexture.js
+++ b/src/core/textures/BaseTexture.js
@@ -114,6 +114,38 @@
this.cacheId = null;
this.validate();
+
+ /**
+ * Fired when a not-immediately-available source finishes loading.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#loaded
+ * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
+ */
+
+ /**
+ * Fired when a not-immediately-available source fails to load.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#error
+ * @param {PIXI.BaseTexture} baseTexture - Resource errored.
+ */
+
+ /**
+ * Fired when BaseTexture is updated.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#update
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
+ */
+
+ /**
+ * Fired when BaseTexture is destroyed.
+ *
+ * @protected
+ * @event PIXI.BaseTexture#dispose
+ * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
+ */
}
setResource(resource)
diff --git a/src/core/textures/Spritesheet.js b/src/core/textures/Spritesheet.js
index d469c62..9b24f27 100644
--- a/src/core/textures/Spritesheet.js
+++ b/src/core/textures/Spritesheet.js
@@ -208,6 +208,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage functions
TextureCache[i] = this.textures[i];
+ this.textures[i].textureCacheId = i;
}
frameIndex++;
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 0a2c379..2213087 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -147,9 +147,9 @@
/**
* Fired when the texture is updated. This happens if the frame or the baseTexture is updated.
*
- * @event update
- * @memberof PIXI.Texture#
+ * @event PIXI.Texture#update
* @protected
+ * @param {PIXI.Texture} texture - Instance of texture being updated.
*/
this._updateID = 0;
@@ -159,6 +159,15 @@
* @type {Object}
*/
this.transform = null;
+
+ /**
+ * The id under which this Texture has been added to the texture cache. This is
+ * automatically set in certain cases, but may not always be accurate, particularly if
+ * the texture is in the cache under multiple ids.
+ *
+ * @member {string}
+ */
+ this.textureCacheId = null;
}
/**
@@ -225,11 +234,17 @@
this._uvs = null;
this.trim = null;
this.orig = null;
+ this.textureCacheId = null;
this.valid = false;
- this.off('dispose', this.dispose, this);
- this.off('update', this.update, this);
+ for (const prop in TextureCache)
+ {
+ if (TextureCache[prop] === this)
+ {
+ delete TextureCache[prop];
+ }
+ }
}
/**
@@ -315,14 +330,15 @@
*/
static fromLoader(source, imageUrl, name)
{
- // console.log('added from loader...')
+ // console.log('added from loader...')
const resource = new ImageResource(source);//.from(imageUrl, crossorigin);// document.createElement('img');
- // console.log('base resource ' + resource.width);
+ // console.log('base resource ' + resource.width);
const baseTexture = new BaseTexture(resource,
settings.SCALE_MODE,
getResolutionOfUrl(imageUrl));
+
/// console.log('base width ' + baseTexture.width);
const texture = new Texture(baseTexture);
@@ -335,6 +351,7 @@
// lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
BaseTextureCache[name] = baseTexture;
TextureCache[name] = texture;
+ texture.textureCacheId = name;
// also add references by url if they are different.
if (name !== imageUrl)
@@ -355,6 +372,10 @@
*/
static addTextureToCache(texture, id)
{
+ if (!texture.textureCacheId)
+ {
+ texture.textureCacheId = id;
+ }
TextureCache[id] = texture;
}
@@ -495,6 +516,7 @@
*/
Texture.EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture.EMPTY);
+removeAllHandlers(Texture.EMPTY.baseTexture);
/**
* A white texture of 10x10 size, used for graphics and other things
@@ -505,3 +527,4 @@
*/
Texture.WHITE = createWhiteTexture();
removeAllHandlers(Texture.WHITE);
+removeAllHandlers(Texture.WHITE.baseTexture);
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index 59eb9fd..a9b9f51 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -1,6 +1,7 @@
import BaseTexture from './BaseTexture';
import { uid, BaseTextureCache } from '../utils';
-import * as ticker from '../ticker';
+import { shared } from '../ticker';
+import { UPDATE_PRIORITY } from '../const';
/**
* A texture of a [playing] Video.
@@ -125,7 +126,7 @@
if (!this._isAutoUpdating && this.autoUpdate)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
@@ -139,7 +140,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
}
@@ -187,7 +188,7 @@
{
if (this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
}
if (this.source && this.source._pixiId)
@@ -281,12 +282,12 @@
if (!this._autoUpdate && this._isAutoUpdating)
{
- ticker.shared.remove(this.update, this);
+ shared.remove(this.update, this);
this._isAutoUpdating = false;
}
else if (this._autoUpdate && !this._isAutoUpdating)
{
- ticker.shared.add(this.update, this);
+ shared.add(this.update, this, UPDATE_PRIORITY.HIGH);
this._isAutoUpdating = true;
}
}
diff --git a/src/core/ticker/Ticker.js b/src/core/ticker/Ticker.js
index 17a1517..40df138 100644
--- a/src/core/ticker/Ticker.js
+++ b/src/core/ticker/Ticker.js
@@ -1,12 +1,10 @@
import settings from '../settings';
-import EventEmitter from 'eventemitter3';
-
-// Internal event used by composed emitter
-const TICK = 'tick';
+import { UPDATE_PRIORITY } from '../const';
+import TickerListener from './TickerListener';
/**
* A Ticker class that runs an update loop that other objects listen to.
- * This class is composed around an EventEmitter object to add listeners
+ * This class is composed around listeners
* meant for execution on the next requested animation frame.
* Animation frames are requested only when necessary,
* e.g. When the ticker is started and the emitter has listeners.
@@ -22,10 +20,11 @@
constructor()
{
/**
- * Internal emitter used to fire 'tick' event
+ * The first listener. All new listeners added are chained on this.
* @private
+ * @type {TickerListener}
*/
- this._emitter = new EventEmitter();
+ this._head = new TickerListener(null, null, Infinity);
/**
* Internal current frame request ID
@@ -131,7 +130,7 @@
// Invoke listeners now
this.update(time);
// Listener side effects may have modified ticker state.
- if (this.started && this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this.started && this._requestId === null && this._head.next)
{
this._requestId = requestAnimationFrame(this._tick);
}
@@ -148,7 +147,7 @@
*/
_requestIfNeeded()
{
- if (this._requestId === null && this._emitter.listeners(TICK, true))
+ if (this._requestId === null && this._head.next)
{
// ensure callbacks get correct delta
this.lastTime = performance.now();
@@ -193,35 +192,72 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#on} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Register a handler for tick events. Calls continuously unless
+ * it is removed or the ticker is stopped.
*
* @param {Function} fn - The listener function to be added for updates
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- add(fn, context)
+ add(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.on(TICK, fn, context);
-
- this._startIfPossible();
-
- return this;
+ return this._addListener(new TickerListener(fn, context, priority));
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#once} internally for the
- * internal 'tick' event. It checks if the emitter has listeners,
- * and if so it requests a new animation frame at this point.
+ * Add a handler for the tick event which is only execute once.
*
* @param {Function} fn - The listener function to be added for one update
* @param {Function} [context] - The listener context
+ * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
- addOnce(fn, context)
+ addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL)
{
- this._emitter.once(TICK, fn, context);
+ return this._addListener(new TickerListener(fn, context, priority, true));
+ }
+
+ /**
+ * Internally adds the event handler so that it can be sorted by priority.
+ * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run
+ * before the rendering.
+ *
+ * @private
+ * @param {TickerListener} listener - Current listener being added.
+ * @returns {PIXI.ticker.Ticker} This instance of a ticker
+ */
+ _addListener(listener)
+ {
+ // For attaching to head
+ let current = this._head.next;
+ let previous = this._head;
+
+ // Add the first item
+ if (!current)
+ {
+ listener.connect(previous);
+ }
+ else
+ {
+ // Go from highest to lowest priority
+ while (current)
+ {
+ if (listener.priority >= current.priority)
+ {
+ listener.connect(previous);
+ break;
+ }
+ previous = current;
+ current = current.next;
+ }
+
+ // Not yet connected
+ if (!listener.previous)
+ {
+ listener.connect(previous);
+ }
+ }
this._startIfPossible();
@@ -229,19 +265,33 @@
}
/**
- * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event.
- * It checks if the emitter has listeners for 'tick' event.
- * If it does, then it cancels the animation frame.
+ * Removes any handlers matching the function and context parameters.
+ * If no handlers are left after removing, then it cancels the animation frame.
*
- * @param {Function} [fn] - The listener function to be removed
+ * @param {Function} fn - The listener function to be removed
* @param {Function} [context] - The listener context to be removed
* @returns {PIXI.ticker.Ticker} This instance of a ticker
*/
remove(fn, context)
{
- this._emitter.off(TICK, fn, context);
+ let listener = this._head.next;
- if (!this._emitter.listeners(TICK, true))
+ while (listener)
+ {
+ // We found a match, lets remove it
+ // no break to delete all possible matches
+ // incase a listener was added 2+ times
+ if (listener.match(fn, context))
+ {
+ listener = listener.destroy();
+ }
+ else
+ {
+ listener = listener.next;
+ }
+ }
+
+ if (!this._head.next)
{
this._cancelIfNeeded();
}
@@ -276,6 +326,25 @@
}
/**
+ * Destroy the ticker and don't use after this. Calling
+ * this method removes all references to internal events.
+ */
+ destroy()
+ {
+ this.stop();
+
+ let listener = this._head.next;
+
+ while (listener)
+ {
+ listener = listener.destroy(true);
+ }
+
+ this._head.destroy();
+ this._head = null;
+ }
+
+ /**
* Triggers an update. An update entails setting the
* current {@link PIXI.ticker.Ticker#elapsedMS},
* the current {@link PIXI.ticker.Ticker#deltaTime},
@@ -320,8 +389,22 @@
this.deltaTime = elapsedMS * settings.TARGET_FPMS * this.speed;
+ // Cache a local reference, in-case ticker is destroyed
+ // during the emit, we can still check for head.next
+ const head = this._head;
+
// Invoke listeners added to internal emitter
- this._emitter.emit(TICK, this.deltaTime);
+ let listener = head.next;
+
+ while (listener)
+ {
+ listener = listener.emit(this.deltaTime);
+ }
+
+ if (!head.next)
+ {
+ this._cancelIfNeeded();
+ }
}
else
{
diff --git a/src/core/ticker/TickerListener.js b/src/core/ticker/TickerListener.js
new file mode 100644
index 0000000..2bedb34
--- /dev/null
+++ b/src/core/ticker/TickerListener.js
@@ -0,0 +1,158 @@
+/**
+ * Internal class for handling the priority sorting of ticker handlers.
+ *
+ * @private
+ * @class
+ * @memberof PIXI.ticker
+ */
+export default class TickerListener
+{
+ /**
+ * Constructor
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} [context=null] - The listener context
+ * @param {number} [priority=0] - The priority for emitting
+ * @param {boolean} [once=false] - If the handler should fire once
+ */
+ constructor(fn, context = null, priority = 0, once = false)
+ {
+ /**
+ * The handler function to execute.
+ * @member {Function}
+ */
+ this.fn = fn;
+
+ /**
+ * The calling to execute.
+ * @member {Function}
+ */
+ this.context = context;
+
+ /**
+ * The current priority.
+ * @member {number}
+ */
+ this.priority = priority;
+
+ /**
+ * If this should only execute once.
+ * @member {boolean}
+ */
+ this.once = once;
+
+ /**
+ * The next item in chain.
+ * @member {TickerListener}
+ */
+ this.next = null;
+
+ /**
+ * The previous item in chain.
+ * @member {TickerListener}
+ */
+ this.previous = null;
+
+ /**
+ * `true` if this listener has been destroyed already.
+ * @member {boolean}
+ * @private
+ */
+ this._destroyed = false;
+ }
+
+ /**
+ * Simple compare function to figure out if a function and context match.
+ *
+ * @param {Function} fn - The listener function to be added for one update
+ * @param {Function} context - The listener context
+ * @return {boolean} `true` if the listener match the arguments
+ */
+ match(fn, context)
+ {
+ context = context || null;
+
+ return this.fn === fn && this.context === context;
+ }
+
+ /**
+ * Emit by calling the current function.
+ * @param {number} deltaTime - time since the last emit.
+ * @return {TickerListener} Next ticker
+ */
+ emit(deltaTime)
+ {
+ if (this.context)
+ {
+ this.fn.call(this.context, deltaTime);
+ }
+ else
+ {
+ this.fn(deltaTime);
+ }
+
+ if (this.once)
+ {
+ this.destroy();
+ }
+
+ const redirect = this.next;
+
+ // Soft-destroying should remove
+ // the next reference
+ if (this._destroyed)
+ {
+ this.next = null;
+ }
+
+ return redirect;
+ }
+
+ /**
+ * Connect to the list.
+ * @param {TickerListener} previous - Input node, previous listener
+ */
+ connect(previous)
+ {
+ this.previous = previous;
+ if (previous.next)
+ {
+ previous.next.previous = this;
+ }
+ this.next = previous.next;
+ previous.next = this;
+ }
+
+ /**
+ * Destroy and don't use after this.
+ * @param {boolean} [hard = false] `true` to remove the `next` reference, this
+ * is considered a hard destroy. Soft destroy maintains the next reference.
+ * @return {TickerListener} The listener to redirect while emitting or removing.
+ */
+ destroy(hard = false)
+ {
+ this._destroyed = true;
+ this.fn = null;
+ this.context = null;
+
+ // Disconnect, hook up next and previous
+ if (this.previous)
+ {
+ this.previous.next = this.next;
+ }
+
+ if (this.next)
+ {
+ this.next.previous = this.previous;
+ }
+
+ // Redirect to the next item
+ const redirect = this.previous;
+
+ // Remove references
+ this.next = hard ? null : redirect;
+ this.previous = null;
+
+ return redirect;
+ }
+}
diff --git a/src/core/ticker/index.js b/src/core/ticker/index.js
index 4b3017c..c3020d4 100644
--- a/src/core/ticker/index.js
+++ b/src/core/ticker/index.js
@@ -45,8 +45,25 @@
const shared = new Ticker();
shared.autoStart = true;
+shared.destroy = () =>
+{
+ // protect destroying shared ticker
+ // this is used by other internal systems
+ // like AnimatedSprite and InteractionManager
+};
/**
+ * This namespace contains an API for interacting with PIXI's internal global update loop.
+ *
+ * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite},
+ * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems.
+ * @example
+ * const ticker = new PIXI.ticker.Ticker();
+ * ticker.stop();
+ * ticker.add((deltaTime) => {
+ * // do something every frame
+ * });
+ * ticker.start();
* @namespace PIXI.ticker
*/
export { shared, Ticker };
diff --git a/src/core/utils/index.js b/src/core/utils/index.js
index be44750..7441f7b 100644
--- a/src/core/utils/index.js
+++ b/src/core/utils/index.js
@@ -9,6 +9,21 @@
let saidHello = false;
/**
+ * Generalized convenience utilities for PIXI.
+ * @example
+ * // Extend PIXI's internal Event Emitter.
+ * class MyEmitter extends PIXI.utils.EventEmitter {
+ * constructor() {
+ * super();
+ * console.log("Emitter created!");
+ * }
+ * }
+ *
+ * // Get info on current device
+ * console.log(PIXI.utils.isMobile);
+ *
+ * // Convert hex color to string
+ * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff"
* @namespace PIXI.utils
*/
export {
diff --git a/src/deprecation.js b/src/deprecation.js
index b9c73b3..33daeec 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -918,6 +918,35 @@
});
/**
+ * @method
+ * @name PIXI.prepare.BasePrepare#register
+ * @see PIXI.prepare.BasePrepare#registerFindHook
+ * @deprecated since version 4.4.2
+ * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+prepare.BasePrepare.prototype.register = function register(addHook, uploadHook)
+{
+ warn('renderer.plugins.prepare.register is now deprecated, '
+ + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook');
+
+ if (addHook)
+ {
+ this.registerFindHook(addHook);
+ }
+
+ if (uploadHook)
+ {
+ this.registerUploadHook(uploadHook);
+ }
+
+ return this;
+};
+
+/**
* The number of graphics or textures to upload to the GPU.
*
* @name PIXI.prepare.canvas.UPLOADS_PER_FRAME
@@ -969,67 +998,73 @@
},
});
-Object.defineProperties(loaders.Resource.prototype, {
- isJson: {
- get()
- {
- warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+if (loaders.Loader)
+{
+ const Resource = loaders.Resource;
+ const Loader = loaders.Loader;
- return this.type === loaders.Loader.Resource.TYPE.JSON;
+ Object.defineProperties(Resource.prototype, {
+ isJson: {
+ get()
+ {
+ warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.');
+
+ return this.type === Resource.TYPE.JSON;
+ },
},
- },
- isXml: {
- get()
- {
- warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
+ isXml: {
+ get()
+ {
+ warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.');
- return this.type === loaders.Loader.Resource.TYPE.XML;
+ return this.type === Resource.TYPE.XML;
+ },
},
- },
- isImage: {
- get()
- {
- warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
+ isImage: {
+ get()
+ {
+ warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.');
- return this.type === loaders.Loader.Resource.TYPE.IMAGE;
+ return this.type === Resource.TYPE.IMAGE;
+ },
},
- },
- isAudio: {
- get()
- {
- warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
+ isAudio: {
+ get()
+ {
+ warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.');
- return this.type === loaders.Loader.Resource.TYPE.AUDIO;
+ return this.type === Resource.TYPE.AUDIO;
+ },
},
- },
- isVideo: {
- get()
- {
- warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
+ isVideo: {
+ get()
+ {
+ warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.');
- return this.type === loaders.Loader.Resource.TYPE.VIDEO;
+ return this.type === Resource.TYPE.VIDEO;
+ },
},
- },
-});
+ });
-Object.defineProperties(loaders.Loader.prototype, {
- before: {
- get()
- {
- warn('The before() method is deprecated, please use pre().');
+ Object.defineProperties(Loader.prototype, {
+ before: {
+ get()
+ {
+ warn('The before() method is deprecated, please use pre().');
- return this.pre;
+ return this.pre;
+ },
},
- },
- after: {
- get()
- {
- warn('The after() method is deprecated, please use use().');
+ after: {
+ get()
+ {
+ warn('The after() method is deprecated, please use use().');
- return this.use;
+ return this.use;
+ },
},
- },
-});
+ });
+}
/**
* @name PIXI.interaction.interactiveTarget#defaultCursor
diff --git a/src/extract/canvas/CanvasExtract.js b/src/extract/canvas/CanvasExtract.js
index 941ca05..3ac5aee 100644
--- a/src/extract/canvas/CanvasExtract.js
+++ b/src/extract/canvas/CanvasExtract.js
@@ -8,7 +8,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class CanvasExtract
{
@@ -21,9 +21,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.CanvasExtract} extract
+ * @member {PIXI.extract.CanvasExtract} extract
* @memberof PIXI.CanvasRenderer#
- * @see PIXI.CanvasExtract
+ * @see PIXI.extract.CanvasExtract
*/
renderer.extract = this;
}
diff --git a/src/extract/index.js b/src/extract/index.js
index 0f2170d..e9478c1 100644
--- a/src/extract/index.js
+++ b/src/extract/index.js
@@ -1,2 +1,22 @@
+/**
+ * This namespace provides renderer-specific plugins for exporting content from a renderer.
+ * For instance, these plugins can be used for saving an Image, Canvas element or for exporting the raw image data (pixels).
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new app (will auto-add extract plugin to renderer)
+ * const app = new PIXI.Application();
+ *
+ * // Draw a red circle
+ * const graphics = new PIXI.Graphics()
+ * .beginFill(0xFF0000)
+ * .drawCircle(0, 0, 50);
+ *
+ * // Render the graphics as an HTMLImageElement
+ * const image = app.renderer.plugins.extract.image(graphics);
+ * document.body.appendChild(image);
+ * @namespace PIXI.extract
+ */
export { default as webgl } from './webgl/WebGLExtract';
export { default as canvas } from './canvas/CanvasExtract';
diff --git a/src/extract/webgl/WebGLExtract.js b/src/extract/webgl/WebGLExtract.js
index 60228bb..1c3dd30 100644
--- a/src/extract/webgl/WebGLExtract.js
+++ b/src/extract/webgl/WebGLExtract.js
@@ -9,7 +9,7 @@
* An instance of this class is automatically created by default, and can be found at renderer.plugins.extract
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extract
*/
export default class WebGLExtract
{
@@ -22,9 +22,9 @@
/**
* Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture
*
- * @member {PIXI.WebGLExtract} extract
+ * @member {PIXI.extract.WebGLExtract} extract
* @memberof PIXI.WebGLRenderer#
- * @see PIXI.WebGLExtract
+ * @see PIXI.extract.WebGLExtract
*/
renderer.extract = this;
}
diff --git a/src/extras/AnimatedSprite.js b/src/extras/AnimatedSprite.js
index 13b804f..5297778 100644
--- a/src/extras/AnimatedSprite.js
+++ b/src/extras/AnimatedSprite.js
@@ -137,7 +137,7 @@
this.playing = true;
if (this._autoUpdate)
{
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH);
}
}
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
index 78e6e40..16536d2 100644
--- a/src/extras/TextureTransform.js
+++ b/src/extras/TextureTransform.js
@@ -65,8 +65,36 @@
}
/**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
* updates matrices if texture was changed
* @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
*/
update(forceUpdate)
{
@@ -74,13 +102,13 @@
if (!tex || !tex.valid)
{
- return;
+ return false;
}
if (!forceUpdate
&& this._lastTextureID === tex._updateID)
{
- return;
+ return false;
}
this._lastTextureID = tex._updateID;
@@ -110,5 +138,7 @@
frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
this.uClampOffset[0] = offset / texBase.realWidth;
this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
}
}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 1f6014f..a3f027f 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -180,9 +180,9 @@
const transform = this.worldTransform;
const resolution = renderer.resolution;
const baseTexture = texture.baseTexture;
- const baseTextureResolution = texture.baseTexture.resolution;
- const modX = (this.tilePosition.x / this.tileScale.x) % texture._frame.width;
- const modY = (this.tilePosition.y / this.tileScale.y) % texture._frame.height;
+ const baseTextureResolution = baseTexture.resolution;
+ const modX = ((this.tilePosition.x / this.tileScale.x) % texture._frame.width) * baseTextureResolution;
+ const modY = ((this.tilePosition.y / this.tileScale.y) % texture._frame.height) * baseTextureResolution;
// create a nice shiny pattern!
// TODO this needs to be refreshed if texture changes..
diff --git a/src/extras/cacheAsBitmap.js b/src/extras/cacheAsBitmap.js
index 5dd5640..aea06a8 100644
--- a/src/extras/cacheAsBitmap.js
+++ b/src/extras/cacheAsBitmap.js
@@ -227,7 +227,16 @@
this.transform._parentID = -1;
// restore the transform of the cached sprite to avoid the nasty flicker..
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
// map the hit test..
this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
@@ -314,7 +323,17 @@
cachedSprite._bounds = this._bounds;
cachedSprite.alpha = cacheAlpha;
- this.updateTransform();
+ if (!this.parent)
+ {
+ this.parent = renderer._tempDisplayObjectParent;
+ this.updateTransform();
+ this.parent = null;
+ }
+ else
+ {
+ this.updateTransform();
+ }
+
this.updateTransform = this.displayObjectUpdateTransform;
this._cacheData.sprite = cachedSprite;
@@ -358,9 +377,12 @@
* Destroys the cached object.
*
* @private
+ * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
+ * have been set to that value.
+ * Used when destroying containers, see the Container.destroy method.
*/
-DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy()
+DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options)
{
this.cacheAsBitmap = false;
- this.destroy();
+ this.destroy(options);
};
diff --git a/src/extras/index.js b/src/extras/index.js
index bbd8bbf..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -1,7 +1,7 @@
/**
+ * Additional PIXI DisplayObjects for animation, tiling and bitmap text.
* @namespace PIXI.extras
*/
-export { default as TextureTransform } from './TextureTransform';
export { default as AnimatedSprite } from './AnimatedSprite';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
diff --git a/src/extras/webgl/TilingSpriteRenderer.js b/src/extras/webgl/TilingSpriteRenderer.js
index aeec172..eee3b5c 100644
--- a/src/extras/webgl/TilingSpriteRenderer.js
+++ b/src/extras/webgl/TilingSpriteRenderer.js
@@ -11,7 +11,7 @@
* WebGL renderer plugin for tiling sprites
*
* @class
- * @memberof PIXI
+ * @memberof PIXI.extras
* @extends PIXI.ObjectRenderer
*/
export default class TilingSpriteRenderer extends core.ObjectRenderer
@@ -118,7 +118,7 @@
tempMat.invert();
if (isSimple)
{
- tempMat.append(uv.mapCoord);
+ tempMat.prepend(uv.mapCoord);
}
else
{
diff --git a/src/filters/displacement/DisplacementFilter.js b/src/filters/displacement/DisplacementFilter.js
index d5355c3..b5d030c 100644
--- a/src/filters/displacement/DisplacementFilter.js
+++ b/src/filters/displacement/DisplacementFilter.js
@@ -35,7 +35,7 @@
this.maskSprite = sprite;
this.maskMatrix = maskMatrix;
- this.uniforms.mapSampler = sprite.texture;
+ this.uniforms.mapSampler = sprite._texture;
this.uniforms.filterMatrix = maskMatrix;
this.uniforms.scale = { x: 1, y: 1 };
diff --git a/src/filters/index.js b/src/filters/index.js
index f3e8862..7ceb50a 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -1,4 +1,21 @@
/**
+ * This namespace contains WebGL-only display filters that can be applied
+ * to DisplayObjects using the {@link PIXI.DisplayObject#filters filters} property.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ *
+ * // Draw a green rectangle
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add a blur filter
+ * rect.filters = [new PIXI.filters.BlurFilter()];
+ *
+ * // Display rectangle
+ * app.stage.addChild(rect);
+ * document.body.appendChild(app.view);
* @namespace PIXI.filters
*/
export { default as FXAAFilter } from './fxaa/FXAAFilter';
diff --git a/src/index.js b/src/index.js
index c553427..77da490 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,14 @@
import { utils } from './core';
utils.mixins.performMixins();
+/**
+ * Alias for {@link PIXI.loaders.shared}.
+ * @name loader
+ * @memberof PIXI
+ * @type {PIXI.loader.Loader}
+ */
+const loader = loaders.shared || null;
+
export {
accessibility,
extract,
@@ -30,18 +38,8 @@
mesh,
particles,
prepare,
+ loader,
};
-/**
- * A premade instance of the loader that can be used to load resources.
- *
- * @name loader
- * @memberof PIXI
- * @property {PIXI.loaders.Loader}
- */
-const loader = loaders && loaders.Loader ? new loaders.Loader() : null; // check is there in case user excludes loader lib
-
-export { loader };
-
// Always export pixi globally.
global.PIXI = exports; // eslint-disable-line
diff --git a/src/interaction/InteractionData.js b/src/interaction/InteractionData.js
index 02d53a3..449f8cc 100644
--- a/src/interaction/InteractionData.js
+++ b/src/interaction/InteractionData.js
@@ -30,7 +30,10 @@
/**
* When passed to an event handler, this will be the original DOM Event that was captured
*
- * @member {Event}
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
+ * @member {MouseEvent|TouchEvent|PointerEvent}
*/
this.originalEvent = null;
}
diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js
index 8baf13a..2d75c7c 100644
--- a/src/interaction/InteractionManager.js
+++ b/src/interaction/InteractionManager.js
@@ -13,6 +13,14 @@
const MOUSE_POINTER_ID = 'MOUSE';
+// helpers for hitTest() - only used inside hitTest()
+const hitTestEvent = {
+ target: null,
+ data: {
+ global: null,
+ },
+};
+
/**
* The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive
* if its interactive parameter is set to true
@@ -245,67 +253,60 @@
this.setTargetElement(this.renderer.view, this.renderer.resolution);
/**
- * Fired when a pointer device button (usually a mouse button) is pressed on the display
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display
* object.
*
- * @event mousedown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* on the display object.
*
- * @event rightdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released over the display
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
* object.
*
- * @event mouseup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is released
* over the display object.
*
- * @event rightup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is pressed and released on
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
* the display object.
*
- * @event click
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device secondary button (usually a mouse right-button) is pressed
* and released on the display object.
*
- * @event rightclick
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
- * Fired when a pointer device button (usually a mouse button) is released outside the
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
* display object that initially registered a
* [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}.
*
- * @event mouseupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
@@ -313,146 +314,362 @@
* outside the display object that initially registered a
* [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}.
*
- * @event rightupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved while over the display object
*
- * @event mousemove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved onto the display object
*
- * @event mouseover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device (usually a mouse) is moved off the display object
*
- * @event mouseout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed on the display object.
*
- * @event pointerdown
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released over the display object.
*
- * @event pointerup
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a pointer event
*
- * @event pointercancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is pressed and released on the display object.
*
- * @event pointertap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device button is released outside the display object that initially
* registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}.
*
- * @event pointerupoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved while over the display object
*
- * @event pointermove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved onto the display object
*
- * @event pointerover
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a pointer device is moved off the display object
*
- * @event pointerout
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed on the display object.
*
- * @event touchstart
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed from the display object.
*
- * @event touchend
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when the operating system cancels a touch
*
- * @event touchcancel
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is placed and removed from the display object.
*
- * @event tap
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is removed outside of the display object that initially
* registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}.
*
- * @event touchendoutside
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
/**
* Fired when a touch point is moved along the display object.
*
- * @event touchmove
- * @type {PIXI.interaction.InteractionData}
- * @memberof PIXI.interaction.InteractionManager#
+ * @event PIXI.interaction.InteractionManager#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
*/
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousedown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released over the display
+ * object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is pressed and released on
+ * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#click
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is pressed
+ * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightclick
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button (usually a mouse left-button) is released outside the
+ * display object that initially registered a
+ * [mousedown]{@link PIXI.DisplayObject#event:mousedown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device secondary button (usually a mouse right-button) is released
+ * outside the display object that initially registered a
+ * [rightdown]{@link PIXI.DisplayObject#event:rightdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#rightupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mousemove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device (usually a mouse) is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#mouseout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerdown
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerup
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a pointer event.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointercancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is pressed and released on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointertap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device button is released outside the display object that initially
+ * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerupoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved while over the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointermove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved onto the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerover
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a pointer device is moved off the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#pointerout
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed on the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchstart
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchend
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when the operating system cancels a touch.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchcancel
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is placed and removed from the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#tap
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is removed outside of the display object that initially
+ * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchendoutside
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+
+ /**
+ * Fired when a touch point is moved along the display object.
+ * DisplayObject's `interactive` property must be set to `true` to fire event.
+ *
+ * @event PIXI.DisplayObject#touchmove
+ * @param {PIXI.interaction.InteractionData} event - Interaction data
+ */
+ }
+
+ /**
+ * Hit tests a point against the display tree, returning the first interactive object that is hit.
+ *
+ * @param {PIXI.Point} globalPoint - A point to hit test with, in global space.
+ * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults
+ * to the last rendered root of the associated renderer.
+ * @return {PIXI.DisplayObject} The hit display object, if any.
+ */
+ hitTest(globalPoint, root)
+ {
+ // clear the target for our hit test
+ hitTestEvent.target = null;
+ // assign the global point
+ hitTestEvent.data.global = globalPoint;
+ // ensure safety of the root
+ if (!root)
+ {
+ root = this.renderer._lastObjectRendered;
+ }
+ // run the hit test
+ this.processInteractive(hitTestEvent, root, null, true);
+ // return our found object - it'll be null if we didn't hit anything
+
+ return hitTestEvent.target;
}
/**
@@ -487,7 +704,7 @@
return;
}
- core.ticker.shared.add(this.update, this);
+ core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION);
if (window.navigator.msPointerEnabled)
{
@@ -804,8 +1021,6 @@
}
}
- let keepHitTestingAfterChildren = hitTest;
-
// ** FREE TIP **! If an object is not interactive or has no buttons in it
// (such as a game scene!) set interactiveChildren to false for that displayObject.
// This will allow pixi to completely ignore and bypass checking the displayObjects children.
@@ -818,7 +1033,9 @@
const child = children[i];
// time to get recursive.. if this function will return if something is hit..
- if (this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent))
+ const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);
+
+ if (childHit)
{
// its a good idea to check if a child has lost its parent.
// this means it has been removed whilst looping so its best
@@ -827,8 +1044,6 @@
continue;
}
- hit = true;
-
// we no longer need to hit test any more objects in this container as we we
// now know the parent has been hit
interactiveParent = false;
@@ -838,36 +1053,41 @@
// This means we no longer need to hit test anything else. We still need to run
// through all objects, but we don't need to perform any hit tests.
- keepHitTestingAfterChildren = false;
-
- if (child.interactive)
+ if (childHit)
{
- hitTest = false;
+ if (interactionEvent.target)
+ {
+ hitTest = false;
+ }
+ hit = true;
}
-
- // we can break now as we have hit an object.
}
}
}
- hitTest = keepHitTestingAfterChildren;
-
// no point running this if the item is not interactive or does not have an interactive parent.
if (interactive)
{
// if we are hit testing (as in we have no hit any objects yet)
// We also don't need to worry about hit testing if once of the displayObjects children
- // has already been hit!
- if (hitTest && !hit)
+ // has already been hit - but only if it was interactive, otherwise we need to keep
+ // looking for an interactive child, just in case we hit one
+ if (hitTest && !interactionEvent.target)
{
if (displayObject.hitArea)
{
displayObject.worldTransform.applyInverse(point, this._tempPoint);
- hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y);
+ if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y))
+ {
+ hit = true;
+ }
}
else if (displayObject.containsPoint)
{
- hit = displayObject.containsPoint(point);
+ if (displayObject.containsPoint(point))
+ {
+ hit = true;
+ }
}
}
@@ -878,7 +1098,10 @@
interactionEvent.target = displayObject;
}
- func(interactionEvent, displayObject, hit);
+ if (func)
+ {
+ func(interactionEvent, displayObject, !!hit);
+ }
}
}
@@ -914,7 +1137,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -998,7 +1221,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1098,7 +1321,7 @@
const test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;
- const isDown = trackingData !== undefined && (trackingData.flags | test);
+ const isDown = trackingData !== undefined && (trackingData.flags & test);
if (hit)
{
@@ -1118,11 +1341,11 @@
{
if (isRightButton)
{
- trackingData.rightDown = hit;
+ trackingData.rightDown = false;
}
else
{
- trackingData.leftDown = hit;
+ trackingData.leftDown = false;
}
}
}
@@ -1180,7 +1403,7 @@
{
const event = events[i];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1255,7 +1478,7 @@
this.setCursorMode(null);
}
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1268,6 +1491,12 @@
{
this.emit('mouseout', interactionEvent);
}
+ else
+ {
+ // we can get touchleave events after touchend, so we want to make sure we don't
+ // introduce memory leaks
+ this.releaseInteractionDataForPointerId(interactionData.identifier);
+ }
}
/**
@@ -1344,7 +1573,7 @@
// Only mouse and pointer can call onPointerOver, so events will always be length 1
const event = events[0];
- const interactionData = this.getInteractionDataForPointerId(event.pointerId);
+ const interactionData = this.getInteractionDataForPointerId(event);
const interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);
@@ -1366,12 +1595,14 @@
* Get InteractionData for a given pointerId. Store that data as well
*
* @private
- * @param {number} pointerId - Identifier from a pointer event
+ * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData
* @return {InteractionData} - Interaction data for the given pointer identifier
*/
- getInteractionDataForPointerId(pointerId)
+ getInteractionDataForPointerId(event)
{
- if (pointerId === MOUSE_POINTER_ID)
+ const pointerId = event.pointerId;
+
+ if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse')
{
return this.mouse;
}
diff --git a/src/interaction/InteractionTrackingData.js b/src/interaction/InteractionTrackingData.js
index 6a1f69e..8493b63 100644
--- a/src/interaction/InteractionTrackingData.js
+++ b/src/interaction/InteractionTrackingData.js
@@ -35,8 +35,10 @@
}
/**
+ * Unique pointer id of the event
+ *
* @readonly
- * @type {number} Unique pointer id of the event
+ * @member {number}
*/
get pointerId()
{
diff --git a/src/interaction/index.js b/src/interaction/index.js
index 56c5b09..72f7d71 100644
--- a/src/interaction/index.js
+++ b/src/interaction/index.js
@@ -1,4 +1,8 @@
/**
+ * This namespace contains a renderer plugin for handling mouse, pointer, and touch events.
+ *
+ * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
* @namespace PIXI.interaction
*/
export { default as InteractionData } from './InteractionData';
diff --git a/src/interaction/interactiveTarget.js b/src/interaction/interactiveTarget.js
index d252fba..cebac40 100644
--- a/src/interaction/interactiveTarget.js
+++ b/src/interaction/interactiveTarget.js
@@ -2,7 +2,7 @@
* Default property values of interactive objects
* Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties
*
- * @mixin
+ * @private
* @name interactiveTarget
* @memberof PIXI.interaction
* @example
@@ -14,18 +14,28 @@
* );
*/
export default {
+
/**
- * Determines if the displayObject be clicked/touched
+ * Enable interaction events for the DisplayObject. Touch, pointer and mouse
+ * events will not be emitted unless `interactive` is set to `true`.
*
- * @inner {boolean}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.on('tap', (event) => {
+ * //handle event
+ * });
+ * @member {boolean}
+ * @memberof PIXI.DisplayObject#
*/
interactive: false,
/**
* Determines if the children to the displayObject can be clicked/touched
- * Setting this to false allows pixi to bypass a recursive hitTest function
+ * Setting this to false allows pixi to bypass a recursive `hitTest` function
*
- * @inner {boolean}
+ * @member {boolean}
+ * @memberof PIXI.Container#
*/
interactiveChildren: true,
@@ -33,7 +43,12 @@
* Interaction shape. Children will be hit first, then this shape will be checked.
* Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds.
*
- * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
+ * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle}
+ * @memberof PIXI.DisplayObject#
*/
hitArea: null,
@@ -41,8 +56,12 @@
* If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive
* Setting this changes the 'cursor' property to `'pointer'`.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.buttonMode = true;
* @member {boolean}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
*/
get buttonMode()
{
@@ -64,9 +83,14 @@
* This defines what cursor mode is used when the mouse cursor
* is hovered over the displayObject.
*
+ * @example
+ * const sprite = new PIXI.Sprite(texture);
+ * sprite.interactive = true;
+ * sprite.cursor = 'wait';
* @see https://developer.mozilla.org/en/docs/Web/CSS/cursor
*
- * @inner {string}
+ * @member {string}
+ * @memberof PIXI.DisplayObject#
*/
cursor: null,
@@ -74,7 +98,7 @@
* Internal set of all active pointers, by identifier
*
* @member {Map}
- * @memberof PIXI.interaction.interactiveTarget#
+ * @memberof PIXI.DisplayObject#
* @private
*/
get trackedPointers()
@@ -87,7 +111,8 @@
/**
* Map of all tracked pointers, by identifier. Use trackedPointers to access.
*
- * @private {Map}
+ * @private
+ * @type {Map}
*/
_trackedPointers: undefined,
};
diff --git a/src/loaders/index.js b/src/loaders/index.js
index 5189793..daa1fc4 100644
--- a/src/loaders/index.js
+++ b/src/loaders/index.js
@@ -1,9 +1,22 @@
+import Application from '../core/Application';
+import Loader from './loader';
+
/**
+ * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module
+ * for loading assets, data, and other resources dynamically.
+ * @example
+ * const loader = new PIXI.loaders.Loader();
+ * loader.add('bunny', 'data/bunny.png')
+ * .add('spaceship', 'assets/spritesheet.json');
+ * loader.load((loader, resources) => {
+ * // resources.bunny
+ * // resources.spaceship
+ * });
* @namespace PIXI.loaders
*/
-export { default as Loader } from './loader';
+export { Loader };
export { default as bitmapFontParser, parse as parseBitmapFontData } from './bitmapFontParser';
-export { default as spritesheetParser } from './spritesheetParser';
+export { default as spritesheetParser, getResourcePath } from './spritesheetParser';
export { default as textureParser } from './textureParser';
/**
@@ -13,3 +26,55 @@
* @memberof PIXI.loaders
*/
export { Resource } from 'resource-loader';
+
+/**
+ * A premade instance of the loader that can be used to load resources.
+ * @name shared
+ * @memberof PIXI.loaders
+ * @type {PIXI.loaders.Loader}
+ */
+const shared = new Loader();
+
+shared.destroy = () =>
+{
+ // protect destroying shared loader
+};
+
+export { shared };
+
+// Mixin the loader construction
+const AppPrototype = Application.prototype;
+
+AppPrototype._loader = null;
+
+/**
+ * Loader instance to help with asset loading.
+ * @name PIXI.Application#loader
+ * @type {PIXI.loaders.Loader}
+ */
+Object.defineProperty(AppPrototype, 'loader', {
+ get()
+ {
+ if (!this._loader)
+ {
+ const sharedLoader = this._options.sharedLoader;
+
+ this._loader = sharedLoader ? shared : new Loader();
+ }
+
+ return this._loader;
+ },
+});
+
+// Override the destroy function
+// making sure to destroy the current Loader
+AppPrototype._parentDestroy = AppPrototype.destroy;
+AppPrototype.destroy = function destroy()
+{
+ if (this._loader)
+ {
+ this._loader.destroy();
+ this._loader = null;
+ }
+ this._parentDestroy();
+};
diff --git a/src/loaders/loader.js b/src/loaders/loader.js
index 767a411..59b8000 100644
--- a/src/loaders/loader.js
+++ b/src/loaders/loader.js
@@ -90,6 +90,15 @@
{
Loader._pixiMiddleware.push(fn);
}
+
+ /**
+ * Destroy the loader, removes references.
+ */
+ destroy()
+ {
+ this.removeAllListeners();
+ this.reset();
+ }
}
// Copy EE3 prototype (mixin)
diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js
index e57dfb2..eda9584 100644
--- a/src/loaders/spritesheetParser.js
+++ b/src/loaders/spritesheetParser.js
@@ -1,12 +1,11 @@
import { Resource } from 'resource-loader';
-import path from 'path';
+import url from 'url';
import { Spritesheet } from '../core';
export default function ()
{
return function spritesheetParser(resource, next)
{
- let resourcePath;
const imageResourceName = `${resource.name}_image`;
// skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
@@ -28,15 +27,7 @@
parentResource: resource,
};
- // Prepend url path unless the resource image is a data url
- if (resource.isDataUrl)
- {
- resourcePath = resource.data.meta.image;
- }
- else
- {
- resourcePath = `${path.dirname(resource.url.replace(this.baseUrl, ''))}/${resource.data.meta.image}`;
- }
+ const resourcePath = getResourcePath(resource, this.baseUrl);
// load the image for this sheet
this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res)
@@ -56,3 +47,14 @@
});
};
}
+
+export function getResourcePath(resource, baseUrl)
+{
+ // Prepend url path unless the resource image is a data url
+ if (resource.isDataUrl)
+ {
+ return resource.data.meta.image;
+ }
+
+ return url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
+}
diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js
index 297205f..f7899e1 100644
--- a/src/mesh/canvas/CanvasMeshRenderer.js
+++ b/src/mesh/canvas/CanvasMeshRenderer.js
@@ -134,12 +134,33 @@
const textureWidth = base.width;
const textureHeight = base.height;
- const u0 = uvs[index0] * base.width;
- const u1 = uvs[index1] * base.width;
- const u2 = uvs[index2] * base.width;
- const v0 = uvs[index0 + 1] * base.height;
- const v1 = uvs[index1 + 1] * base.height;
- const v2 = uvs[index2 + 1] * base.height;
+ let u0;
+ let u1;
+ let u2;
+ let v0;
+ let v1;
+ let v2;
+
+ if (mesh.uploadUvTransform)
+ {
+ const ut = mesh._uvTransform.mapCoord;
+
+ u0 = ((uvs[index0] * ut.a) + (uvs[index0 + 1] * ut.c) + ut.tx) * base.width;
+ u1 = ((uvs[index1] * ut.a) + (uvs[index1 + 1] * ut.c) + ut.tx) * base.width;
+ u2 = ((uvs[index2] * ut.a) + (uvs[index2 + 1] * ut.c) + ut.tx) * base.width;
+ v0 = ((uvs[index0] * ut.b) + (uvs[index0 + 1] * ut.d) + ut.ty) * base.height;
+ v1 = ((uvs[index1] * ut.b) + (uvs[index1 + 1] * ut.d) + ut.ty) * base.height;
+ v2 = ((uvs[index2] * ut.b) + (uvs[index2 + 1] * ut.d) + ut.ty) * base.height;
+ }
+ else
+ {
+ u0 = uvs[index0] * base.width;
+ u1 = uvs[index1] * base.width;
+ u2 = uvs[index2] * base.width;
+ v0 = uvs[index0 + 1] * base.height;
+ v1 = uvs[index1 + 1] * base.height;
+ v2 = uvs[index2 + 1] * base.height;
+ }
let x0 = vertices[index0];
let x1 = vertices[index1];
diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js
index 78d24c3..ab99fcd 100644
--- a/src/mesh/webgl/MeshRenderer.js
+++ b/src/mesh/webgl/MeshRenderer.js
@@ -2,6 +2,8 @@
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
+const matrixIdentity = core.Matrix.IDENTITY;
+
/**
* WebGL renderer plugin for tiling sprites
*
@@ -64,6 +66,7 @@
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start, mesh.geometry.instanceCount);
}
+
/**
* draws mesh
* @param {PIXI.mesh.RawMesh} mesh mesh instance
diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert
index a337aef..acc096c 100644
--- a/src/mesh/webgl/mesh.vert
+++ b/src/mesh/webgl/mesh.vert
@@ -1,8 +1,9 @@
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
-uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
+uniform mat3 translationMatrix;
+uniform mat3 uTransform;
varying vec2 vTextureCoord;
@@ -10,5 +11,5 @@
{
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;
}
diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js
index 67796cf..63f7791 100644
--- a/src/particles/ParticleContainer.js
+++ b/src/particles/ParticleContainer.js
@@ -313,10 +313,10 @@
frame.y * resolution,
frame.width * resolution,
frame.height * resolution,
- positionX * resolution,
- positionY * resolution,
- finalWidth * resolution,
- finalHeight * resolution
+ positionX * renderer.resolution,
+ positionY * renderer.resolution,
+ finalWidth * renderer.resolution,
+ finalHeight * renderer.resolution
);
}
}
diff --git a/src/prepare/BasePrepare.js b/src/prepare/BasePrepare.js
index 09eb5e5..e45c4dc 100644
--- a/src/prepare/BasePrepare.js
+++ b/src/prepare/BasePrepare.js
@@ -18,6 +18,18 @@
* basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare}
* to provide preparation capabilities specific to their respective renderers.
*
+ * @example
+ * // Create a sprite
+ * const sprite = new PIXI.Sprite.fromImage('something.png');
+ *
+ * // Load object into GPU
+ * app.renderer.plugins.prepare.upload(sprite, () => {
+ *
+ * //Texture(s) has been uploaded to GPU
+ * app.stage.addChild(sprite);
+ *
+ * })
+ *
* @abstract
* @class
* @memberof PIXI.prepare
@@ -100,8 +112,16 @@
this.prepareItems();
};
- this.register(findText, drawText);
- this.register(findTextStyle, calculateTextStyle);
+ // hooks to find the correct texture
+ this.registerFindHook(findText);
+ this.registerFindHook(findTextStyle);
+ this.registerFindHook(findMultipleBaseTextures);
+ this.registerFindHook(findBaseTexture);
+ this.registerFindHook(findTexture);
+
+ // upload hooks
+ this.registerUploadHook(drawText);
+ this.registerUploadHook(calculateTextStyle);
}
/**
@@ -138,7 +158,7 @@
if (!this.ticking)
{
this.ticking = true;
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
else if (done)
@@ -172,13 +192,16 @@
const item = this.queue[0];
let uploaded = false;
- for (let i = 0, len = this.uploadHooks.length; i < len; i++)
+ if (item && !item._destroyed)
{
- if (this.uploadHooks[i](this.uploadHookHelper, item))
+ for (let i = 0, len = this.uploadHooks.length; i < len; i++)
{
- this.queue.shift();
- uploaded = true;
- break;
+ if (this.uploadHooks[i](this.uploadHookHelper, item))
+ {
+ this.queue.shift();
+ uploaded = true;
+ break;
+ }
}
}
@@ -205,26 +228,36 @@
else
{
// if we are not finished, on the next rAF do this again
- SharedTicker.addOnce(this.tick, this);
+ SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY);
}
}
/**
- * Adds hooks for finding and uploading items.
+ * Adds hooks for finding items.
*
- * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array`
- function must return `true` if it was able to add item to the queue.
- * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
- * function must return `true` if it was able to handle upload of item.
- * @return {PIXI.CanvasPrepare} Instance of plugin for chaining.
+ * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`
+ * function must return `true` if it was able to add item to the queue.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
*/
- register(addHook, uploadHook)
+ registerFindHook(addHook)
{
if (addHook)
{
this.addHooks.push(addHook);
}
+ return this;
+ }
+
+ /**
+ * Adds hooks for uploading items.
+ *
+ * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and
+ * function must return `true` if it was able to handle upload of item.
+ * @return {PIXI.BasePrepare} Instance of plugin for chaining.
+ */
+ registerUploadHook(uploadHook)
+ {
if (uploadHook)
{
this.uploadHooks.push(uploadHook);
@@ -287,6 +320,88 @@
}
/**
+ * Built-in hook to find multiple textures from objects like AnimatedSprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findMultipleBaseTextures(item, queue)
+{
+ let result = false;
+
+ // Objects with mutliple textures
+ if (item && item._textures && item._textures.length)
+ {
+ for (let i = 0; i < item._textures.length; i++)
+ {
+ if (item._textures[i] instanceof core.Texture)
+ {
+ const baseTexture = item._textures[i].baseTexture;
+
+ if (queue.indexOf(baseTexture) === -1)
+ {
+ queue.push(baseTexture);
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Built-in hook to find BaseTextures from Sprites.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findBaseTexture(item, queue)
+{
+ // Objects with textures, like Sprites/Text
+ if (item instanceof core.BaseTexture)
+ {
+ if (queue.indexOf(item) === -1)
+ {
+ queue.push(item);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Built-in hook to find textures from objects.
+ *
+ * @private
+ * @param {PIXI.DisplayObject} item - Display object to check
+ * @param {Array<*>} queue - Collection of items to upload
+ * @return {boolean} if a PIXI.Texture object was found.
+ */
+function findTexture(item, queue)
+{
+ if (item._texture && item._texture instanceof core.Texture)
+ {
+ const texture = item._texture.baseTexture;
+
+ if (queue.indexOf(texture) === -1)
+ {
+ queue.push(texture);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Built-in hook to draw PIXI.Text to its texture.
*
* @private
diff --git a/src/prepare/canvas/CanvasPrepare.js b/src/prepare/canvas/CanvasPrepare.js
index 0224bb5..09c207a 100644
--- a/src/prepare/canvas/CanvasPrepare.js
+++ b/src/prepare/canvas/CanvasPrepare.js
@@ -43,7 +43,7 @@
this.ctx = this.canvas.getContext('2d');
// Add textures to upload
- this.register(findBaseTextures, uploadBaseTextures);
+ this.registerUploadHook(uploadBaseTextures);
}
/**
@@ -89,39 +89,4 @@
return false;
}
-/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item -Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare);
diff --git a/src/prepare/index.js b/src/prepare/index.js
index f559c45..e7491ec 100644
--- a/src/prepare/index.js
+++ b/src/prepare/index.js
@@ -1,4 +1,29 @@
/**
+ * The prepare namespace provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for
+ * asynchronously preparing assets, textures, graphics waiting to be displayed.
+ *
+ * Do not instantiate these plugins directly. It is available from the `renderer.plugins` property.
+ * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.WebGLRenderer#plugins}.
+ * @example
+ * // Create a new application
+ * const app = new PIXI.Application();
+ * document.body.appendChild(app.view);
+ *
+ * // Don't start rendering right away
+ * app.stop();
+ *
+ * // create a display object
+ * const rect = new PIXI.Graphics()
+ * .beginFill(0x00ff00)
+ * .drawRect(40, 40, 200, 200);
+ *
+ * // Add to the stage
+ * app.stage.addChild(rect);
+ *
+ * // Don't start rendering until the graphic is uploaded to the GPU
+ * app.renderer.plugins.prepare.upload(app.stage, () => {
+ * app.start();
+ * });
* @namespace PIXI.prepare
*/
export { default as webgl } from './webgl/WebGLPrepare';
diff --git a/src/prepare/webgl/WebGLPrepare.js b/src/prepare/webgl/WebGLPrepare.js
index eb7023f..9df3c3f 100644
--- a/src/prepare/webgl/WebGLPrepare.js
+++ b/src/prepare/webgl/WebGLPrepare.js
@@ -22,12 +22,11 @@
this.uploadHookHelper = this.renderer;
// Add textures and graphics to upload
- this.register(findBaseTextures, uploadBaseTextures)
- .register(findGraphics, uploadGraphics);
+ this.registerFindHook(findGraphics);
+ this.registerUploadHook(uploadBaseTextures);
+ this.registerUploadHook(uploadGraphics);
}
-
}
-
/**
* Built-in hook to upload PIXI.Texture objects to the GPU.
*
@@ -80,41 +79,6 @@
}
/**
- * Built-in hook to find textures from Sprites.
- *
- * @private
- * @param {PIXI.DisplayObject} item - Display object to check
- * @param {Array<*>} queue - Collection of items to upload
- * @return {boolean} if a PIXI.Texture object was found.
- */
-function findBaseTextures(item, queue)
-{
- // Objects with textures, like Sprites/Text
- if (item instanceof core.BaseTexture)
- {
- if (queue.indexOf(item) === -1)
- {
- queue.push(item);
- }
-
- return true;
- }
- else if (item._texture && item._texture instanceof core.Texture)
- {
- const texture = item._texture.baseTexture;
-
- if (queue.indexOf(texture) === -1)
- {
- queue.push(texture);
- }
-
- return true;
- }
-
- return false;
-}
-
-/**
* Built-in hook to find graphics.
*
* @private
diff --git a/test/.eslintrc.json b/test/.eslintrc.json
index e03220d..ac12110 100644
--- a/test/.eslintrc.json
+++ b/test/.eslintrc.json
@@ -12,7 +12,8 @@
"sinon": false,
"expect": false,
"assert": false,
- "PIXI": false
+ "PIXI": false,
+ "PointerEvent": true
},
"rules": {
"func-names": 0,
diff --git a/test/core/BaseTexture.js b/test/core/BaseTexture.js
index 8b93478..bb65068 100644
--- a/test/core/BaseTexture.js
+++ b/test/core/BaseTexture.js
@@ -14,4 +14,28 @@
expect(baseTexture.imageType).to.be.equals('png');
});
});
+
+ it('should remove Canvas BaseTexture from cache on destroy', function ()
+ {
+ const canvas = document.createElement('canvas');
+ const texture = PIXI.BaseTexture.fromCanvas(canvas);
+ const _pixiId = canvas._pixiId;
+
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.BaseTextureCache[_pixiId]).to.equal(undefined);
+ });
+
+ it('should remove Image BaseTexture from cache on destroy', function ()
+ {
+ const URL = 'foo.png';
+ const NAME = 'bar';
+ const image = new Image();
+
+ const texture = PIXI.Texture.fromLoader(image, URL, NAME);
+
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(texture.baseTexture);
+ texture.destroy(true);
+ expect(PIXI.utils.BaseTextureCache[NAME]).to.equal(undefined);
+ });
});
diff --git a/test/core/Circle.js b/test/core/Circle.js
index 183f98f..f621992 100644
--- a/test/core/Circle.js
+++ b/test/core/Circle.js
@@ -53,6 +53,10 @@
expect(circ1.contains(10, 16)).to.be.false;
expect(circ1.contains(11, 15)).to.be.false;
expect(circ1.contains(0, 0)).to.be.false;
+
+ const circ2 = new PIXI.Circle(10, 10, 0);
+
+ expect(circ2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Container.js b/test/core/Container.js
index d11be33..cefde54 100644
--- a/test/core/Container.js
+++ b/test/core/Container.js
@@ -2,30 +2,36 @@
function testAddChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.addChild(obj);
- });
- fn(function (container, obj)
- {
- container.addChildAt(obj);
- });
+ fn(function (container, obj)
+ {
+ container.addChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.addChildAt(obj);
+ });
+ };
}
function testRemoveChild(fn)
{
- fn(function (container, obj)
+ return function ()
{
- container.removeChild(obj);
- });
- fn(function (container, obj)
- {
- container.removeChildAt(container.children.indexOf(obj));
- });
- fn(function (container, obj)
- {
- container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
- });
+ fn(function (container, obj)
+ {
+ container.removeChild(obj);
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildAt(container.children.indexOf(obj));
+ });
+ fn(function (container, obj)
+ {
+ container.removeChildren(container.children.indexOf(obj), container.children.indexOf(obj) + 1);
+ });
+ };
}
describe('PIXI.Container', function ()
diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js
index f2e8234..3f47442 100644
--- a/test/core/Ellipse.js
+++ b/test/core/Ellipse.js
@@ -56,6 +56,10 @@
expect(ellipse1.contains(10, 16)).to.be.false;
expect(ellipse1.contains(11, 15)).to.be.false;
expect(ellipse1.contains(0, 0)).to.be.false;
+
+ const ellipse2 = new PIXI.Ellipse(10, 10, 0, 0);
+
+ expect(ellipse2.contains(10, 10)).to.be.false;
});
it('should return framing rectangle', function ()
diff --git a/test/core/Matrix.js b/test/core/Matrix.js
index 9d2694b..76bd57c 100644
--- a/test/core/Matrix.js
+++ b/test/core/Matrix.js
@@ -107,10 +107,60 @@
expect(m1.ty).to.equal(m2.ty);
});
+ it('should prepend matrix', function ()
+ {
+ const m1 = new PIXI.Matrix();
+ const m2 = new PIXI.Matrix();
+
+ m2.set(2, 3, 4, 5, 100, 200);
+ m1.prepend(m2);
+
+ expect(m1.a).to.equal(m2.a);
+ expect(m1.b).to.equal(m2.b);
+ expect(m1.c).to.equal(m2.c);
+ expect(m1.d).to.equal(m2.d);
+ expect(m1.tx).to.equal(m2.tx);
+ expect(m1.ty).to.equal(m2.ty);
+
+ const m3 = new PIXI.Matrix();
+ const m4 = new PIXI.Matrix();
+
+ m3.prepend(m4);
+
+ expect(m3.a).to.equal(m4.a);
+ expect(m3.b).to.equal(m4.b);
+ expect(m3.c).to.equal(m4.c);
+ expect(m3.d).to.equal(m4.d);
+ expect(m3.tx).to.equal(m4.tx);
+ expect(m3.ty).to.equal(m4.ty);
+ });
+
it('should get IDENTITY and TEMP_MATRIX', function ()
{
expect(PIXI.Matrix.IDENTITY instanceof PIXI.Matrix).to.be.true;
expect(PIXI.Matrix.TEMP_MATRIX instanceof PIXI.Matrix).to.be.true;
});
-});
+ it('should reset matrix to default when identity() is called', function ()
+ {
+ const matrix = new PIXI.Matrix();
+
+ matrix.set(2, 3, 4, 5, 100, 200);
+
+ expect(matrix.a).to.equal(2);
+ expect(matrix.b).to.equal(3);
+ expect(matrix.c).to.equal(4);
+ expect(matrix.d).to.equal(5);
+ expect(matrix.tx).to.equal(100);
+ expect(matrix.ty).to.equal(200);
+
+ matrix.identity();
+
+ expect(matrix.a).to.equal(1);
+ expect(matrix.b).to.equal(0);
+ expect(matrix.c).to.equal(0);
+ expect(matrix.d).to.equal(1);
+ expect(matrix.tx).to.equal(0);
+ expect(matrix.ty).to.equal(0);
+ });
+});
diff --git a/test/core/Spritesheet.js b/test/core/Spritesheet.js
index 283adf5..7601a0c 100644
--- a/test/core/Spritesheet.js
+++ b/test/core/Spritesheet.js
@@ -18,6 +18,7 @@
expect(textures[id]).to.be.an.instanceof(PIXI.Texture);
expect(textures[id].width).to.equal(spritesheet.data.frames[id].frame.w / spritesheet.resolution);
expect(textures[id].height).to.equal(spritesheet.data.frames[id].frame.h / spritesheet.resolution);
+ expect(textures[id].textureCacheId).to.equal(id);
spritesheet.destroy(true);
expect(spritesheet.textures).to.be.null;
expect(spritesheet.baseTexture).to.be.null;
diff --git a/test/core/Texture.js b/test/core/Texture.js
index 8c4ef98..241ec3e 100644
--- a/test/core/Texture.js
+++ b/test/core/Texture.js
@@ -16,4 +16,20 @@
expect(PIXI.utils.TextureCache[URL]).to.equal(texture);
expect(PIXI.utils.BaseTextureCache[URL]).to.equal(texture.baseTexture);
});
+
+ it('should remove Texture from cache on destroy', function ()
+ {
+ const NAME = 'foo';
+ const NAME2 = 'bar';
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+
+ PIXI.Texture.addTextureToCache(texture, NAME);
+ PIXI.Texture.addTextureToCache(texture, NAME2);
+ expect(texture.textureCacheId).to.equal(NAME);
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(texture);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(texture);
+ texture.destroy();
+ expect(PIXI.utils.TextureCache[NAME]).to.equal(undefined);
+ expect(PIXI.utils.TextureCache[NAME2]).to.equal(undefined);
+ });
});
diff --git a/test/core/Ticker.js b/test/core/Ticker.js
new file mode 100644
index 0000000..188770f
--- /dev/null
+++ b/test/core/Ticker.js
@@ -0,0 +1,322 @@
+'use strict';
+
+const Ticker = PIXI.ticker.Ticker;
+const shared = PIXI.ticker.shared;
+
+describe('PIXI.ticker.Ticker', function ()
+{
+ before(function ()
+ {
+ this.length = (ticker) =>
+ {
+ ticker = ticker || shared;
+
+ if (!ticker._head || !ticker._head.next)
+ {
+ return 0;
+ }
+
+ let listener = ticker._head.next;
+ let i = 0;
+
+ while (listener)
+ {
+ listener = listener.next;
+ i++;
+ }
+
+ return i;
+ };
+ });
+
+ it('should be available', function ()
+ {
+ expect(Ticker).to.be.a.function;
+ expect(shared).to.be.an.instanceof(Ticker);
+ });
+
+ it('should create a new ticker and destroy it', function ()
+ {
+ const ticker = new Ticker();
+
+ ticker.start();
+
+ const listener = sinon.spy();
+
+ expect(this.length(ticker)).to.equal(0);
+
+ ticker.add(listener);
+
+ expect(this.length(ticker)).to.equal(1);
+
+ ticker.destroy();
+
+ expect(ticker._head).to.be.null;
+ expect(ticker.started).to.be.false;
+ expect(this.length(ticker)).to.equal(0);
+ });
+
+ it('should protect destroying shared ticker', function ()
+ {
+ shared.destroy();
+ expect(shared._head).to.not.be.null;
+ expect(shared.started).to.be.true;
+ });
+
+ it('should add and remove listener', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener);
+
+ expect(this.length()).to.equal(length + 1);
+
+ shared.remove(listener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should update a listener', function ()
+ {
+ const listener = sinon.spy();
+
+ shared.add(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ });
+
+ it('should update a listener twice and remove once', function ()
+ {
+ const listener = sinon.spy();
+ const length = this.length();
+
+ shared.add(listener).add(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length + 2);
+
+ shared.remove(listener);
+ shared.update();
+
+ expect(listener.calledTwice).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should respect priority order', function ()
+ {
+ const length = this.length();
+ const listener1 = sinon.spy();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.LOW)
+ .add(listener4, null, PIXI.UPDATE_PRIORITY.INTERACTION)
+ .add(listener3, null, PIXI.UPDATE_PRIORITY.HIGH)
+ .add(listener2, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 4);
+
+ sinon.assert.callOrder(listener4, listener3, listener2, listener1);
+
+ shared.remove(listener1)
+ .remove(listener2)
+ .remove(listener3)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should auto-remove once listeners', function ()
+ {
+ const length = this.length();
+ const listener = sinon.spy();
+
+ shared.addOnce(listener);
+
+ shared.update();
+
+ expect(listener.calledOnce).to.be.true;
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should call inserted item with a lower priority', function ()
+ {
+ const length = this.length();
+ const lowListener = sinon.spy();
+ const highListener = sinon.spy();
+ const mainListener = sinon.spy(() =>
+ {
+ shared.add(highListener, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(lowListener, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(mainListener, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 3);
+
+ expect(mainListener.calledOnce).to.be.true;
+ expect(lowListener.calledOnce).to.be.true;
+ expect(highListener.calledOnce).to.be.false;
+
+ shared.remove(mainListener)
+ .remove(highListener)
+ .remove(lowListener);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove emit low-priority item during emit', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself on emit after adding new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.remove(listener1);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove itself before, still calling new item', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener1);
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 1);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 1);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.remove(listener2);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should remove items before and after current priority', function ()
+ {
+ const length = this.length();
+ const listener2 = sinon.spy();
+ const listener3 = sinon.spy();
+ const listener4 = sinon.spy();
+
+ shared.add(listener2, null, PIXI.UPDATE_PRIORITY.HIGH);
+ shared.add(listener3, null, PIXI.UPDATE_PRIORITY.LOW);
+ shared.add(listener4, null, PIXI.UPDATE_PRIORITY.LOW);
+
+ const listener1 = sinon.spy(() =>
+ {
+ shared.remove(listener2)
+ .remove(listener3);
+
+ // listener is removed right away
+ expect(this.length()).to.equal(length + 2);
+ });
+
+ shared.add(listener1, null, PIXI.UPDATE_PRIORITY.NORMAL);
+
+ shared.update();
+
+ expect(this.length()).to.equal(length + 2);
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledOnce).to.be.true;
+ expect(listener1.calledOnce).to.be.true;
+
+ shared.update();
+
+ expect(listener2.calledOnce).to.be.true;
+ expect(listener3.calledOnce).to.be.false;
+ expect(listener4.calledTwice).to.be.true;
+ expect(listener1.calledTwice).to.be.true;
+
+ shared.remove(listener1)
+ .remove(listener4);
+
+ expect(this.length()).to.equal(length);
+ });
+
+ it('should destroy on listener', function (done)
+ {
+ const ticker = new Ticker();
+ const listener2 = sinon.spy();
+ const listener = sinon.spy(() =>
+ {
+ ticker.destroy();
+ setTimeout(() =>
+ {
+ expect(listener2.called).to.be.false;
+ expect(listener.calledOnce).to.be.true;
+ done();
+ }, 0);
+ });
+
+ ticker.add(listener);
+ ticker.add(listener2, null, PIXI.UPDATE_PRIORITY.LOW);
+ ticker.start();
+ });
+});
diff --git a/test/core/TilingSprite.js b/test/core/TilingSprite.js
index 2e449a7..7694792 100644
--- a/test/core/TilingSprite.js
+++ b/test/core/TilingSprite.js
@@ -24,4 +24,25 @@
expect(bounds.height).to.equal(600);
});
});
+
+ it('checks if tilingSprite contains a point', function ()
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+ const tilingSprite = new PIXI.extras.TilingSprite(texture, 200, 300);
+
+ expect(tilingSprite.containsPoint(new PIXI.Point(1, 1))).to.equal(true);
+ expect(tilingSprite.containsPoint(new PIXI.Point(300, 400))).to.equal(false);
+ });
+
+ it('gets and sets height and width correctly', function ()
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture());
+ const tilingSprite = new PIXI.extras.TilingSprite(texture, 200, 300);
+
+ tilingSprite.width = 400;
+ tilingSprite.height = 600;
+
+ expect(tilingSprite.width).to.equal(400);
+ expect(tilingSprite.height).to.equal(600);
+ });
});
diff --git a/test/core/index.js b/test/core/index.js
index 8530131..58dc30e 100755
--- a/test/core/index.js
+++ b/test/core/index.js
@@ -17,6 +17,7 @@
require('./util');
require('./Plane');
require('./Point');
+require('./Polygon');
require('./ObservablePoint');
require('./Matrix');
require('./Rectangle');
@@ -27,4 +28,5 @@
require('./WebGLRenderer');
require('./Ellipse');
require('./Texture');
+require('./Ticker');
require('./filters');
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 0e7e707..31385b9 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -4,6 +4,16 @@
describe('PIXI.interaction.InteractionManager', function ()
{
+ afterEach(function ()
+ {
+ // if we made a MockPointer for the test, clean it up
+ if (this.pointer)
+ {
+ this.pointer.cleanUp();
+ this.pointer = null;
+ }
+ });
+
describe('event basics', function ()
{
it('should call mousedown handler', function ()
@@ -11,7 +21,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -29,7 +39,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -47,7 +57,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -66,7 +76,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -84,7 +94,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const eventSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -286,7 +296,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -304,7 +314,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -316,6 +326,29 @@
expect(clickSpy).to.not.have.been.called;
});
+
+ it('should not call handler when mousedown not received', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const clickSpy = sinon.spy();
+ const pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+ graphics.on('click', clickSpy);
+
+ pointer.mouseup(10, 10);
+
+ expect(clickSpy, 'click should not happen on first mouseup').to.not.have.been.called;
+
+ // test again, just because it was a bug that was reported
+ pointer.mouseup(20, 20);
+
+ expect(clickSpy, 'click should not happen on second mouseup').to.not.have.been.called;
+ });
});
describe('onTap', function ()
@@ -325,7 +358,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -343,7 +376,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const clickSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -359,32 +392,62 @@
describe('overlapping children', function ()
{
- function getScene(callbackEventName)
+ function getScene(callbackEventName, splitParents)
{
const behindChild = new PIXI.Graphics();
const frontChild = new PIXI.Graphics();
const parent = new PIXI.Container();
- const behindChildCallback = sinon.spy();
- const frontChildCallback = sinon.spy();
- const parentCallback = sinon.spy();
+ const behindChildCallback = sinon.spy(function behindSpy() { /* no op*/ });
+ const frontChildCallback = sinon.spy(function frontSpy() { /* no op*/ });
+ const parentCallback = sinon.spy(function parentSpy() { /* no op*/ });
+ let behindParent;
+ let frontParent;
+ let behindParentCallback;
+ let frontParentCallback;
behindChild.beginFill(0xFF);
behindChild.drawRect(0, 0, 50, 50);
behindChild.on(callbackEventName, behindChildCallback);
+ behindChild.name = 'behind';
frontChild.beginFill(0x00FF);
frontChild.drawRect(0, 0, 50, 50);
frontChild.on(callbackEventName, frontChildCallback);
+ frontChild.name = 'front';
- parent.addChild(behindChild, frontChild);
+ if (splitParents)
+ {
+ behindParent = new PIXI.Container();
+ behindParent.name = 'behindParent';
+ frontParent = new PIXI.Container();
+ frontParent.name = 'frontParent';
+ behindParentCallback = sinon.spy(function behindParentSpy() { /* no op*/ });
+ frontParentCallback = sinon.spy(function frontParentSpy() { /* no op*/ });
+ behindParent.on(callbackEventName, behindParentCallback);
+ frontParent.on(callbackEventName, frontParentCallback);
+
+ parent.addChild(behindParent, frontParent);
+ behindParent.addChild(behindChild);
+ frontParent.addChild(frontChild);
+
+ parent.name = 'parent';
+ }
+ else
+ {
+ parent.addChild(behindChild, frontChild);
+ }
parent.on(callbackEventName, parentCallback);
return {
behindChild,
frontChild,
+ behindParent,
+ frontParent,
parent,
behindChildCallback,
frontChildCallback,
+ behindParentCallback,
+ frontParentCallback,
parentCallback,
};
}
@@ -396,7 +459,7 @@
it('should callback front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -414,7 +477,7 @@
it('should callback front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -432,7 +495,7 @@
it('should callback behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -446,6 +509,48 @@
expect(scene.behindChildCallback).to.have.been.calledOnce;
expect(scene.parentCallback).to.not.have.been.called;
});
+
+ it('should callback front child of different non-interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.not.have.been.called;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.not.have.been.called;
+ });
+
+ it('should callback front child of different interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+ scene.behindParent.interactive = true;
+ scene.frontParent.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.not.have.been.called;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.have.been.calledOnce;
+ });
});
describe('when front child is non-interactive', function ()
@@ -453,7 +558,7 @@
it('should not callback when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -470,7 +575,7 @@
it('should callback behind child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -487,7 +592,7 @@
it('should callback behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -507,7 +612,7 @@
it('should callback front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -524,7 +629,7 @@
it('should callback front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -541,7 +646,7 @@
it('should not callback when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -564,7 +669,7 @@
it('should callback parent and front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -583,7 +688,7 @@
it('should callback parent and front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -602,7 +707,7 @@
it('should callback parent and behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -617,6 +722,50 @@
expect(scene.behindChildCallback).to.have.been.calledOnce;
expect(scene.parentCallback).to.have.been.calledOnce;
});
+
+ it('should callback front child of different non-interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+ scene.parent.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.have.been.calledOnce;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.not.have.been.called;
+ });
+
+ it('should callback front child of different interactive parents when clicking overlap', function ()
+ {
+ const stage = new PIXI.Container();
+ const pointer = this.pointer = new MockPointer(stage);
+ const scene = getScene('click', true);
+
+ scene.behindChild.interactive = true;
+ scene.behindChild.x = 25;
+ scene.frontChild.interactive = true;
+ scene.parent.interactive = true;
+ scene.behindParent.interactive = true;
+ scene.frontParent.interactive = true;
+
+ stage.addChild(scene.parent);
+ pointer.click(40, 10);
+
+ expect(scene.behindChildCallback).to.not.have.been.called;
+ expect(scene.frontChildCallback).to.have.been.calledOnce;
+ expect(scene.parentCallback).to.have.been.calledOnce;
+ expect(scene.behindParentCallback).to.not.have.been.called;
+ expect(scene.frontParentCallback).to.have.been.calledOnce;
+ });
});
describe('when front child is non-interactive', function ()
@@ -624,7 +773,7 @@
it('should callback parent when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -642,7 +791,7 @@
it('should callback parent and behind child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -660,7 +809,7 @@
it('should callback parent and behind child when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.interactive = true;
@@ -681,7 +830,7 @@
it('should callback parent and front child when clicking front child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -699,7 +848,7 @@
it('should callback parent and front child when clicking overlap', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -717,7 +866,7 @@
it('should callback parent when clicking behind child', function ()
{
const stage = new PIXI.Container();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
const scene = getScene('click');
scene.behindChild.x = 25;
@@ -733,6 +882,42 @@
});
});
});
+
+ it('Semi-complicated nesting with overlap, should not call behind callback', function ()
+ {
+ const stage = new PIXI.Container();
+ const frontParent = new PIXI.Container();
+ const frontChild = new PIXI.Graphics();
+ const behindParent = new PIXI.Container();
+ const subParent = new PIXI.Container();
+ const behindChild = new PIXI.Graphics();
+ const behindCallback = sinon.spy(function behindSpy() { /* no op*/ });
+ const frontCallback = sinon.spy(function frontSpy() { /* no op*/ });
+
+ behindChild.beginFill(0xFF);
+ behindChild.drawRect(0, 0, 50, 50);
+ subParent.on('click', behindCallback);
+
+ frontChild.beginFill(0x00FF);
+ frontChild.drawRect(0, 0, 50, 50);
+ frontParent.on('click', frontCallback);
+ const pointer = this.pointer = new MockPointer(stage);
+
+ behindParent.x = 25;
+ subParent.interactive = true;
+ frontParent.interactive = true;
+
+ behindParent.addChild(subParent);
+ subParent.addChild(behindChild);
+ stage.addChild(behindParent);
+ frontParent.addChild(frontChild);
+ stage.addChild(frontParent);
+
+ pointer.click(40, 10);
+
+ expect(behindCallback).to.not.have.been.called;
+ expect(frontCallback).to.have.been.calledOnce;
+ });
});
describe('cursor changes', function ()
@@ -741,7 +926,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -759,7 +944,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -778,7 +963,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -797,7 +982,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -818,7 +1003,7 @@
const graphics = new PIXI.Graphics();
const overSpy = sinon.spy();
const defaultSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -840,7 +1025,7 @@
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
const defaultSpy = sinon.spy();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -859,7 +1044,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -881,7 +1066,7 @@
{
const stage = new PIXI.Container();
const graphics = new PIXI.Graphics();
- const pointer = new MockPointer(stage);
+ const pointer = this.pointer = new MockPointer(stage);
stage.addChild(graphics);
graphics.beginFill(0xFFFFFF);
@@ -932,7 +1117,7 @@
it('should stop hitTesting after first hit', function ()
{
const scene = getScene();
- const pointer = new MockPointer(scene.stage);
+ const pointer = this.pointer = new MockPointer(scene.stage);
const frontHitTest = sinon.spy(scene.frontChild, 'containsPoint');
const middleHitTest = sinon.spy(scene.middleChild, 'containsPoint');
const behindHitTest = sinon.spy(scene.behindChild, 'containsPoint');
@@ -954,7 +1139,7 @@
it('should stop hitTesting after first hit', function ()
{
const scene = getScene();
- const pointer = new MockPointer(scene.stage);
+ const pointer = this.pointer = new MockPointer(scene.stage);
const frontHitTest = sinon.spy(scene.frontChild, 'containsPoint');
const middleHitTest = sinon.spy(scene.middleChild, 'containsPoint');
const behindHitTest = sinon.spy(scene.behindChild, 'containsPoint');
@@ -971,4 +1156,127 @@
});
});
});
+
+ describe('pointer handling', function ()
+ {
+ it('pointer event from mouse should use single mouse data', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage, 100, 100, true);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.mousemove(20, 10, true);
+
+ expect(pointer.interaction.mouse.global.x).to.equal(20);
+ expect(pointer.interaction.mouse.global.y).to.equal(10);
+ });
+ });
+
+ describe('data cleanup', function ()
+ {
+ it('touchleave after touchout should not orphan data', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.touchstart(10, 10, 42);
+ expect(pointer.interaction.activeInteractionData[42]).to.exist;
+ pointer.touchend(10, 10, 42);
+ expect(pointer.interaction.activeInteractionData[42]).to.be.undefined;
+ pointer.touchleave(10, 10, 42);
+ expect(pointer.interaction.activeInteractionData[42]).to.be.undefined;
+ });
+ });
+
+ describe('hitTest()', function ()
+ {
+ it('should return hit', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(10, 10));
+
+ expect(hit).to.equal(graphics);
+ });
+
+ it('should return null if not hit', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(60, 60));
+
+ expect(hit).to.be.null;
+ });
+
+ it('should return top thing that was hit', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const behind = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(behind);
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+ behind.beginFill(0xFFFFFF);
+ behind.drawRect(0, 0, 50, 50);
+ behind.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(10, 10));
+
+ expect(hit).to.equal(graphics);
+ });
+
+ it('should return hit when passing in root', function ()
+ {
+ const stage = new PIXI.Container();
+ const graphics = new PIXI.Graphics();
+ const behind = new PIXI.Graphics();
+ const pointer = this.pointer = new MockPointer(stage);
+
+ stage.addChild(behind);
+ stage.addChild(graphics);
+ graphics.beginFill(0xFFFFFF);
+ graphics.drawRect(0, 0, 50, 50);
+ graphics.interactive = true;
+ behind.beginFill(0xFFFFFF);
+ behind.drawRect(0, 0, 50, 50);
+ behind.interactive = true;
+
+ pointer.render();
+ const hit = pointer.interaction.hitTest(new PIXI.Point(10, 10), behind);
+
+ expect(hit).to.equal(behind);
+ });
+ });
});
diff --git a/test/interaction/MockPointer.js b/test/interaction/MockPointer.js
index 67878af..c9c6228 100644
--- a/test/interaction/MockPointer.js
+++ b/test/interaction/MockPointer.js
@@ -11,13 +11,43 @@
* @param {PIXI.Container} stage - The root of the scene tree
* @param {number} [width=100] - Width of the renderer
* @param {number} [height=100] - Height of the renderer
+ * @param {boolean} [ensurePointerEvents=false] - If we should make sure that PointerEvents are 'supported'
*/
- constructor(stage, width, height)
+ constructor(stage, width, height, ensurePointerEvents)
{
+ // fake PointerEvent existing
+ if (ensurePointerEvents && !window.PointerEvent)
+ {
+ window.PointerEvent = class PointerEvent extends MouseEvent
+ {
+ //eslint-disable-next-line
+ constructor(type, opts)
+ {
+ super(type, opts);
+ this.pointerType = opts.pointerType;
+ }
+ };
+ this.createdPointerEvent = true;
+ }
+
this.stage = stage;
this.renderer = new PIXI.CanvasRenderer(width || 100, height || 100);
this.renderer.sayHello = () => { /* empty */ };
this.interaction = this.renderer.plugins.interaction;
+ this.interaction.supportsTouchEvents = true;
+ PIXI.ticker.shared.remove(this.interaction.update, this.interaction);
+ }
+
+ /**
+ * Cleans up after tests
+ */
+ cleanup()
+ {
+ if (this.createdPointerEvent)
+ {
+ delete window.PointerEvent;
+ }
+ this.renderer.destroy();
}
/**
@@ -45,14 +75,29 @@
/**
* @param {number} x - pointer x position
* @param {number} y - pointer y position
+ * @param {boolean} [asPointer] - if it should be a PointerEvent from a mouse
*/
- mousemove(x, y)
+ mousemove(x, y, asPointer)
{
- const mouseEvent = new MouseEvent('mousemove', {
- clientX: x,
- clientY: y,
- preventDefault: sinon.stub(),
- });
+ let mouseEvent;
+
+ if (asPointer)
+ {
+ mouseEvent = new PointerEvent('pointermove', {
+ pointerType: 'mouse',
+ clientX: x,
+ clientY: y,
+ preventDefault: sinon.stub(),
+ });
+ }
+ else
+ {
+ mouseEvent = new MouseEvent('mousemove', {
+ clientX: x,
+ clientY: y,
+ preventDefault: sinon.stub(),
+ });
+ }
this.setPosition(x, y);
this.render();
@@ -97,9 +142,15 @@
*/
mousedown(x, y)
{
+ const mouseEvent = new MouseEvent('mousedown', {
+ clientX: x,
+ clientY: y,
+ preventDefault: sinon.stub(),
+ });
+
this.setPosition(x, y);
this.render();
- this.interaction.onMouseDown({ clientX: 0, clientY: 0, preventDefault: sinon.stub() });
+ this.interaction.onPointerDown(mouseEvent);
}
/**
@@ -108,47 +159,83 @@
*/
mouseup(x, y)
{
- this.setPosition(x, y);
- this.render();
- this.interaction.onMouseUp({ clientX: 0, clientY: 0, preventDefault: sinon.stub() });
- }
-
- /**
- * @param {number} x - pointer x position
- * @param {number} y - pointer y position
- */
- tap(x, y)
- {
- this.touchstart(x, y);
- this.touchend(x, y);
- }
-
- /**
- * @param {number} x - pointer x position
- * @param {number} y - pointer y position
- */
- touchstart(x, y)
- {
- this.setPosition(x, y);
- this.render();
- this.interaction.onTouchStart({
+ const mouseEvent = new MouseEvent('mouseup', {
+ clientX: x,
+ clientY: y,
preventDefault: sinon.stub(),
- changedTouches: [new Touch({ identifier: 0, target: this.renderer.view })],
});
+
+ this.setPosition(x, y);
+ this.render();
+ this.interaction.onPointerUp(mouseEvent);
}
/**
* @param {number} x - pointer x position
* @param {number} y - pointer y position
+ * @param {number} [identifier] - pointer id
*/
- touchend(x, y)
+ tap(x, y, identifier)
{
+ this.touchstart(x, y, identifier);
+ this.touchend(x, y, identifier);
+ }
+
+ /**
+ * @param {number} x - pointer x position
+ * @param {number} y - pointer y position
+ * @param {number} [identifier] - pointer id
+ */
+ touchstart(x, y, identifier)
+ {
+ const touchEvent = new TouchEvent('touchstart', {
+ preventDefault: sinon.stub(),
+ changedTouches: [
+ new Touch({ identifier: identifier || 0, target: this.renderer.view }),
+ ],
+ });
+
this.setPosition(x, y);
this.render();
- this.interaction.onTouchEnd({
+ this.interaction.onPointerDown(touchEvent);
+ }
+
+ /**
+ * @param {number} x - pointer x position
+ * @param {number} y - pointer y position
+ * @param {number} [identifier] - pointer id
+ */
+ touchend(x, y, identifier)
+ {
+ const touchEvent = new TouchEvent('touchend', {
preventDefault: sinon.stub(),
- changedTouches: [new Touch({ identifier: 0, target: this.renderer.view })],
+ changedTouches: [
+ new Touch({ identifier: identifier || 0, target: this.renderer.view }),
+ ],
});
+
+ this.setPosition(x, y);
+ this.render();
+ this.interaction.onPointerUp(touchEvent);
+ }
+
+ /**
+ * @param {number} x - pointer x position
+ * @param {number} y - pointer y position
+ * @param {number} [identifier] - pointer id
+ */
+ touchleave(x, y, identifier)
+ {
+ const touchEvent = new TouchEvent('touchleave', {
+ preventDefault: sinon.stub(),
+ changedTouches: [
+ new Touch({ identifier: identifier || 0, target: this.renderer.view }),
+ ],
+ });
+
+ this.setPosition(x, y);
+ this.render();
+ this.interaction.onPointerOut(touchEvent);
}
}
diff --git a/test/loaders/spritesheetParser.js b/test/loaders/spritesheetParser.js
index 79f8c15..4d54805 100644
--- a/test/loaders/spritesheetParser.js
+++ b/test/loaders/spritesheetParser.js
@@ -60,11 +60,46 @@
.that.is.an.instanceof(PIXI.Texture);
});
+ it('should build the image url', function ()
+ {
+ function getResourcePath(url, image)
+ {
+ return PIXI.loaders.getResourcePath({
+ url,
+ data: { meta: { image } },
+ });
+ }
+
+ let result = getResourcePath('http://some.com/spritesheet.json', 'img.png');
+
+ expect(result).to.be.equals('http://some.com/img.png');
+
+ result = getResourcePath('http://some.com/some/dir/spritesheet.json', 'img.png');
+ expect(result).to.be.equals('http://some.com/some/dir/img.png');
+
+ result = getResourcePath('http://some.com/some/dir/spritesheet.json', './img.png');
+ expect(result).to.be.equals('http://some.com/some/dir/img.png');
+
+ result = getResourcePath('http://some.com/some/dir/spritesheet.json', '../img.png');
+ expect(result).to.be.equals('http://some.com/some/img.png');
+
+ result = getResourcePath('/spritesheet.json', 'img.png');
+ expect(result).to.be.equals('/img.png');
+
+ result = getResourcePath('/some/dir/spritesheet.json', 'img.png');
+ expect(result).to.be.equals('/some/dir/img.png');
+
+ result = getResourcePath('/some/dir/spritesheet.json', './img.png');
+ expect(result).to.be.equals('/some/dir/img.png');
+
+ result = getResourcePath('/some/dir/spritesheet.json', '../img.png');
+ expect(result).to.be.equals('/some/img.png');
+ });
+
// TODO: Test that rectangles are created correctly.
// TODO: Test that bathc processing works correctly.
// TODO: Test that resolution processing works correctly.
// TODO: Test that metadata is honored.
- // TODO: Test data-url code paths.
});
function createMockResource(type, data)
diff --git a/test/prepare/BasePrepare.js b/test/prepare/BasePrepare.js
index 03cf2fa..26dc8ad 100644
--- a/test/prepare/BasePrepare.js
+++ b/test/prepare/BasePrepare.js
@@ -10,7 +10,7 @@
expect(prep.renderer).to.equal(renderer);
expect(prep.uploadHookHelper).to.be.null;
expect(prep.queue).to.be.empty;
- expect(prep.addHooks).to.have.lengthOf(2);
+ expect(prep.addHooks).to.have.lengthOf(5);
expect(prep.uploadHooks).to.have.lengthOf(2);
expect(prep.completes).to.be.empty;
@@ -23,10 +23,11 @@
function uploadHook() { /* empty */ }
const prep = new PIXI.prepare.BasePrepare();
- prep.register(addHook, uploadHook);
+ prep.registerFindHook(addHook);
+ prep.registerUploadHook(uploadHook);
expect(prep.addHooks).to.contain(addHook);
- expect(prep.addHooks).to.have.lengthOf(3);
+ expect(prep.addHooks).to.have.lengthOf(6);
expect(prep.uploadHooks).to.contain(uploadHook);
expect(prep.uploadHooks).to.have.lengthOf(3);
@@ -58,7 +59,8 @@
});
const complete = sinon.spy(function () { /* empty */ });
- prep.register(addHook, uploadHook);
+ prep.registerFindHook(addHook);
+ prep.registerUploadHook(uploadHook);
prep.upload(uploadItem, complete);
expect(prep.queue).to.contain(uploadItem);
@@ -82,7 +84,7 @@
}
const complete = sinon.spy(function () { /* empty */ });
- prep.register(addHook);
+ prep.registerFindHook(addHook);
prep.upload({}, complete);
expect(complete.calledOnce).to.be.true;
@@ -106,7 +108,8 @@
});
const complete = sinon.spy(function () { /* empty */ });
- prep.register(addHook, uploadHook);
+ prep.registerFindHook(addHook);
+ prep.registerUploadHook(uploadHook);
prep.upload({}, complete);
expect(prep.queue).to.have.lengthOf(1);
@@ -121,6 +124,41 @@
prep.destroy();
});
+ it('should remove destroyed items from queue', function ()
+ {
+ const prep = new PIXI.prepare.BasePrepare();
+
+ const addHook = sinon.spy(function (item, queue)
+ {
+ queue.push(item);
+
+ return true;
+ });
+ const uploadHook = sinon.spy(function ()
+ {
+ return false;
+ });
+ const complete = sinon.spy(function () { /* empty */ });
+
+ prep.registerFindHook(addHook);
+ prep.registerUploadHook(uploadHook);
+ const item = {};
+
+ prep.upload(item, complete);
+
+ expect(prep.queue).to.have.lengthOf(1);
+
+ item._destroyed = true;
+ prep.prepareItems();
+
+ expect(prep.queue).to.be.empty;
+ expect(addHook.calledOnce).to.be.true;
+ expect(uploadHook.called).to.be.false;
+ expect(complete.calledOnce).to.be.true;
+
+ prep.destroy();
+ });
+
it('should attach to SharedTicker', function (done)
{
const prep = new PIXI.prepare.BasePrepare();
@@ -147,7 +185,8 @@
done();
}
- prep.register(addHook, uploadHook);
+ prep.registerFindHook(addHook);
+ prep.registerUploadHook(uploadHook);
prep.upload({}, complete);
expect(prep.queue).to.have.lengthOf(1);