mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 06:29:02 +08:00
[ts] Refactor module resolution, switch to esbuild
This commit is contained in:
parent
ca6b3d0bac
commit
79f0abf765
6
.gitignore
vendored
6
.gitignore
vendored
@ -149,5 +149,9 @@ cmake-build-debug-visual-studio
|
||||
spine-cocos2dx/build-v4/
|
||||
spine-cocos2dx/example-v4/cocos2d
|
||||
spine-cocos2dx/example-v4/cocos2dx.zip
|
||||
spine-ts/spine-canvas/dist
|
||||
|
||||
spine-ts/spine-core/dist
|
||||
spine-ts/spine-canvas/dist
|
||||
spine-ts/spine-webgl/dist
|
||||
spine-ts/spine-player/dist
|
||||
spine-ts/spine-threejs/dist
|
||||
@ -1,5 +1,7 @@
|
||||
# spine-ts
|
||||
|
||||
# In VS Code config, set Extensions > TypeScript > Import Module Specifier to non-relative
|
||||
|
||||
The spine-ts runtime provides functionality to load and manipulate [Spine](http://esotericsoftware.com) skeletal animation data using TypeScript and JavaScript. spine-ts is split
|
||||
up into multiple modules:
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
3299
spine-ts/build/spine-core.d.ts
vendored
3299
spine-ts/build/spine-core.d.ts
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
261
spine-ts/package-lock.json
generated
261
spine-ts/package-lock.json
generated
@ -15,8 +15,10 @@
|
||||
"spine-webgl"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-typescript": "^8.2.5",
|
||||
"esbuild": "^0.12.22",
|
||||
"npx": "^10.2.2",
|
||||
"rollup": "^2.56.2",
|
||||
"rollup": "^2.56.3",
|
||||
"rollup-plugin-dts": "^3.0.2",
|
||||
"typescript": "^4.3.5"
|
||||
}
|
||||
@ -59,13 +61,50 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@esotericsoftware/spine-canvas": {
|
||||
"resolved": "spine-canvas",
|
||||
"node_modules/@esotericsoftware/spine-webgl": {
|
||||
"resolved": "spine-webgl",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@esotericsoftware/spine-core": {
|
||||
"resolved": "spine-core",
|
||||
"link": true
|
||||
"node_modules/@rollup/plugin-typescript": {
|
||||
"version": "8.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.2.5.tgz",
|
||||
"integrity": "sha512-QL/LvDol/PAGB2O0S7/+q2HpSUNodpw7z6nGn9BfoVCPOZ0r4EALrojFU29Bkoi2Hr2jgTocTejJ5GGWZfOxbQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@rollup/pluginutils": "^3.1.0",
|
||||
"resolve": "^1.17.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^2.14.0",
|
||||
"tslib": "*",
|
||||
"typescript": ">=3.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/pluginutils": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
|
||||
"integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "0.0.39",
|
||||
"estree-walker": "^1.0.1",
|
||||
"picomatch": "^2.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^1.20.0||^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "0.0.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
||||
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
@ -112,6 +151,16 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.12.22",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.22.tgz",
|
||||
"integrity": "sha512-yWCr9RoFehpqoe/+MwZXJpYOEIt7KOEvNnjIeMZpMSyQt+KCBASM3y7yViiN5dJRphf1wGdUz1+M4rTtWd/ulA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
@ -122,6 +171,12 @@
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-walker": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
|
||||
"integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
@ -136,6 +191,24 @@
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
@ -146,6 +219,18 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz",
|
||||
"integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has": "^1.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@ -5203,10 +5288,41 @@
|
||||
"inBundle": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
||||
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.2.0",
|
||||
"path-parse": "^1.0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "2.56.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.2.tgz",
|
||||
"integrity": "sha512-s8H00ZsRi29M2/lGdm1u8DJpJ9ML8SUOpVVBd33XNeEeL3NVaTiUcSBHzBdF3eAyR0l7VSpsuoVUGrRHq7aPwQ==",
|
||||
"version": "2.56.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.3.tgz",
|
||||
"integrity": "sha512-Au92NuznFklgQCUcV96iXlxUbHuB1vQMaH76DHl5M11TotjOHwqk9CwcrT78+Tnv4FN9uTBxq6p4EJoYkpyekg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
@ -5259,6 +5375,13 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
|
||||
@ -5275,17 +5398,18 @@
|
||||
"spine-canvas": {
|
||||
"name": "@esotericsoftware/spine-canvas",
|
||||
"version": "4.0.1",
|
||||
"license": "LicenseRef-LICENSE",
|
||||
"devDependencies": {
|
||||
"npx": "^10.2.2",
|
||||
"rollup": "^2.56.2",
|
||||
"rollup-plugin-dts": "^3.0.2",
|
||||
"typescript": "^4.3.5"
|
||||
}
|
||||
"extraneous": true,
|
||||
"license": "LicenseRef-LICENSE"
|
||||
},
|
||||
"spine-core": {
|
||||
"name": "@esotericsoftware/spine-core",
|
||||
"version": "4.0.1",
|
||||
"extraneous": true,
|
||||
"license": "LicenseRef-LICENSE"
|
||||
},
|
||||
"spine-webgl": {
|
||||
"name": "@esotericsoftware/spine-webgl",
|
||||
"version": "4.0.1",
|
||||
"license": "LicenseRef-LICENSE"
|
||||
}
|
||||
},
|
||||
@ -5319,17 +5443,35 @@
|
||||
"js-tokens": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@esotericsoftware/spine-canvas": {
|
||||
"version": "file:spine-canvas",
|
||||
"@esotericsoftware/spine-webgl": {
|
||||
"version": "file:spine-webgl"
|
||||
},
|
||||
"@rollup/plugin-typescript": {
|
||||
"version": "8.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.2.5.tgz",
|
||||
"integrity": "sha512-QL/LvDol/PAGB2O0S7/+q2HpSUNodpw7z6nGn9BfoVCPOZ0r4EALrojFU29Bkoi2Hr2jgTocTejJ5GGWZfOxbQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"npx": "^10.2.2",
|
||||
"rollup": "^2.56.2",
|
||||
"rollup-plugin-dts": "^3.0.2",
|
||||
"typescript": "^4.3.5"
|
||||
"@rollup/pluginutils": "^3.1.0",
|
||||
"resolve": "^1.17.0"
|
||||
}
|
||||
},
|
||||
"@esotericsoftware/spine-core": {
|
||||
"version": "file:spine-core"
|
||||
"@rollup/pluginutils": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
|
||||
"integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/estree": "0.0.39",
|
||||
"estree-walker": "^1.0.1",
|
||||
"picomatch": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"@types/estree": {
|
||||
"version": "0.0.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
||||
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
@ -5370,6 +5512,12 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild": {
|
||||
"version": "0.12.22",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.22.tgz",
|
||||
"integrity": "sha512-yWCr9RoFehpqoe/+MwZXJpYOEIt7KOEvNnjIeMZpMSyQt+KCBASM3y7yViiN5dJRphf1wGdUz1+M4rTtWd/ulA==",
|
||||
"dev": true
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
@ -5377,6 +5525,12 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"estree-walker": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
|
||||
"integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
|
||||
"dev": true
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
@ -5384,6 +5538,21 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
},
|
||||
"has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
@ -5391,6 +5560,15 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"is-core-module": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz",
|
||||
"integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@ -9345,10 +9523,32 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
|
||||
"dev": true
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
||||
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-core-module": "^2.2.0",
|
||||
"path-parse": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"rollup": {
|
||||
"version": "2.56.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.2.tgz",
|
||||
"integrity": "sha512-s8H00ZsRi29M2/lGdm1u8DJpJ9ML8SUOpVVBd33XNeEeL3NVaTiUcSBHzBdF3eAyR0l7VSpsuoVUGrRHq7aPwQ==",
|
||||
"version": "2.56.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.3.tgz",
|
||||
"integrity": "sha512-Au92NuznFklgQCUcV96iXlxUbHuB1vQMaH76DHl5M11TotjOHwqk9CwcrT78+Tnv4FN9uTBxq6p4EJoYkpyekg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fsevents": "~2.3.2"
|
||||
@ -9380,6 +9580,13 @@
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
|
||||
|
||||
@ -33,8 +33,10 @@
|
||||
"spine-webgl"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-typescript": "^8.2.5",
|
||||
"esbuild": "^0.12.22",
|
||||
"npx": "^10.2.2",
|
||||
"rollup": "^2.56.2",
|
||||
"rollup": "^2.56.3",
|
||||
"rollup-plugin-dts": "^3.0.2",
|
||||
"typescript": "^4.3.5"
|
||||
}
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
import dts from 'rollup-plugin-dts'
|
||||
|
||||
export default [
|
||||
{
|
||||
input: 'spine-core/dist/index.js',
|
||||
context: 'this',
|
||||
output: [
|
||||
{
|
||||
file: 'build/spine-core.js',
|
||||
name: 'spine',
|
||||
format: 'umd',
|
||||
exports: 'named',
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
input: 'spine-core/dist/index.d.ts',
|
||||
output: [{ file: 'build/spine-core.d.ts', format: 'es' }],
|
||||
plugins: [dts()],
|
||||
},
|
||||
|
||||
{
|
||||
input: 'spine-canvas/dist/index.js',
|
||||
context: 'this',
|
||||
output: [
|
||||
{
|
||||
file: 'build/spine-canvas.js',
|
||||
name: 'spine',
|
||||
format: 'umd',
|
||||
exports: 'named',
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Downloader, AssetManagerBase } from "../../spine-core/dist/index";
|
||||
import { AssetManagerBase, Downloader } from "spine-core";
|
||||
import { CanvasTexture } from "./CanvasTexture";
|
||||
|
||||
export class AssetManager extends AssetManagerBase {
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Texture, TextureFilter, TextureWrap } from "../../spine-core/dist/index";
|
||||
import { Texture, TextureFilter, TextureWrap } from "spine-core";
|
||||
|
||||
export class CanvasTexture extends Texture {
|
||||
constructor(image: HTMLImageElement) {
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Utils, Color, Skeleton, RegionAttachment, TextureAtlasRegion, BlendMode, MeshAttachment, Slot } from "../../spine-core/dist/index";
|
||||
import { Utils, Color, Skeleton, RegionAttachment, TextureAtlasRegion, BlendMode, MeshAttachment, Slot } from "spine-core";
|
||||
import { CanvasTexture } from "./CanvasTexture";
|
||||
|
||||
export class SkeletonRenderer {
|
||||
|
||||
@ -1,28 +1,31 @@
|
||||
import { AssetManager } from "./AssetManager";
|
||||
import { CanvasTexture } from "./CanvasTexture";
|
||||
import { SkeletonRenderer } from "./SkeletonRenderer";
|
||||
|
||||
export * from "./AssetManager";
|
||||
export * from "./CanvasTexture";
|
||||
export * from "./SkeletonRenderer";
|
||||
export * from "../../spine-core/dist/index"
|
||||
|
||||
// Needed for compatibility with the old way of how
|
||||
// spine-canvas worked. We'd set all exported types
|
||||
// on the global spine.canvas. However, with rollup
|
||||
// we can only specify a single default object global
|
||||
// name, which is spine, not spine.canvas. If spine-canvas.js
|
||||
// is used in vanilla.js, we added a property spine.canvas
|
||||
// and assign the types of spine-canvas to it. This way
|
||||
// old code keeps on working.
|
||||
export * from "spine-core";
|
||||
|
||||
// Before modularization, we would expose spine-core on the global
|
||||
// `spine` object, and spine-canvas on the global `spine.canvas` object.
|
||||
// This was used by clients when including spine-canvas via <script src="spine-canvas.js">
|
||||
//
|
||||
// Now with modularization and using esbuild for bundling, we need to emulate this old
|
||||
// behaviour as to not break old clients.
|
||||
//
|
||||
// We pass `--global-name=spine` to esbuild. This will create an object containing
|
||||
// all exports and assign it to the global variable called `spine`.
|
||||
//
|
||||
// That solves half the issue. We also need to assign the exports object to
|
||||
// `spine.canvas`. esbuild creates a local variable called `scr_exports` pointing
|
||||
// to the exports object. We get to it via eval, then assign it to itself, on a new
|
||||
// property called `canvas`. The client can then access the APIs through `spine` and
|
||||
// `spine.canvas` as before (with the caveat that both spine-core and spine-canvas are
|
||||
// now in `spine` and `spine.canvas`).
|
||||
//
|
||||
// This will break if esbuild renames the variable `src_exports` pointing to
|
||||
// the exports object.
|
||||
declare global {
|
||||
var spine: any;
|
||||
}
|
||||
|
||||
if (globalThis.spine) {
|
||||
globalThis.spine.canvas = {
|
||||
AssetManager: AssetManager,
|
||||
CanvasTexture: CanvasTexture,
|
||||
SkeletonRenderer: SkeletonRenderer
|
||||
};
|
||||
}
|
||||
let exports = eval("src_exports");
|
||||
exports.canvas = exports;
|
||||
@ -1,9 +1,14 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
"moduleResolution": "node",
|
||||
"paths": {
|
||||
"spine-core": [
|
||||
"../spine-core/src"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
|
||||
26
spine-ts/spine-webgl/package.json
Normal file
26
spine-ts/spine-webgl/package.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@esotericsoftware/spine-webgl",
|
||||
"version": "4.0.1",
|
||||
"description": "The official Spine Runtimes for the web.",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/esotericsoftware/spine-runtimes.git"
|
||||
},
|
||||
"keywords": [
|
||||
"gamedev",
|
||||
"animations",
|
||||
"2d",
|
||||
"spine",
|
||||
"game-dev",
|
||||
"runtimes",
|
||||
"skeletal"
|
||||
],
|
||||
"author": "Esoteric Software LLC",
|
||||
"license": "LicenseRef-LICENSE",
|
||||
"bugs": {
|
||||
"url": "https://github.com/esotericsoftware/spine-runtimes/issues"
|
||||
},
|
||||
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme"
|
||||
}
|
||||
@ -27,12 +27,14 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
export class AssetManager extends spine.AssetManager {
|
||||
constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext, pathPrefix: string = "", downloader: Downloader = null) {
|
||||
super((image: HTMLImageElement | ImageBitmap) => {
|
||||
return new spine.webgl.GLTexture(context, image);
|
||||
}, pathPrefix, downloader);
|
||||
}
|
||||
import { AssetManagerBase, Downloader } from "spine-core";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL";
|
||||
|
||||
|
||||
export class AssetManager extends AssetManagerBase {
|
||||
constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, pathPrefix: string = "", downloader: Downloader = null) {
|
||||
super((image: HTMLImageElement | ImageBitmap) => {
|
||||
return new spine.webgl.GLTexture(context, image);
|
||||
}, pathPrefix, downloader);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,62 +27,63 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
export class OrthoCamera {
|
||||
position = new Vector3(0, 0, 0);
|
||||
direction = new Vector3(0, 0, -1);
|
||||
up = new Vector3(0, 1, 0);
|
||||
near = 0;
|
||||
far = 100;
|
||||
zoom = 1;
|
||||
viewportWidth = 0;
|
||||
viewportHeight = 0;
|
||||
projectionView = new Matrix4();
|
||||
inverseProjectionView = new Matrix4();
|
||||
projection = new Matrix4();
|
||||
view = new Matrix4();
|
||||
import { Matrix4 } from "./Matrix4";
|
||||
import { Vector3 } from "./Vector3";
|
||||
|
||||
constructor (viewportWidth: number, viewportHeight: number) {
|
||||
this.viewportWidth = viewportWidth;
|
||||
this.viewportHeight = viewportHeight;
|
||||
this.update();
|
||||
}
|
||||
export class OrthoCamera {
|
||||
position = new Vector3(0, 0, 0);
|
||||
direction = new Vector3(0, 0, -1);
|
||||
up = new Vector3(0, 1, 0);
|
||||
near = 0;
|
||||
far = 100;
|
||||
zoom = 1;
|
||||
viewportWidth = 0;
|
||||
viewportHeight = 0;
|
||||
projectionView = new Matrix4();
|
||||
inverseProjectionView = new Matrix4();
|
||||
projection = new Matrix4();
|
||||
view = new Matrix4();
|
||||
|
||||
update () {
|
||||
let projection = this.projection;
|
||||
let view = this.view;
|
||||
let projectionView = this.projectionView;
|
||||
let inverseProjectionView = this.inverseProjectionView;
|
||||
let zoom = this.zoom, viewportWidth = this.viewportWidth, viewportHeight = this.viewportHeight;
|
||||
projection.ortho(zoom * (-viewportWidth / 2), zoom * (viewportWidth / 2),
|
||||
zoom * (-viewportHeight / 2), zoom * (viewportHeight / 2),
|
||||
this.near, this.far);
|
||||
view.lookAt(this.position, this.direction, this.up);
|
||||
projectionView.set(projection.values);
|
||||
projectionView.multiply(view);
|
||||
inverseProjectionView.set(projectionView.values).invert();
|
||||
}
|
||||
constructor(viewportWidth: number, viewportHeight: number) {
|
||||
this.viewportWidth = viewportWidth;
|
||||
this.viewportHeight = viewportHeight;
|
||||
this.update();
|
||||
}
|
||||
|
||||
screenToWorld (screenCoords: Vector3, screenWidth: number, screenHeight: number) {
|
||||
let x = screenCoords.x, y = screenHeight - screenCoords.y - 1;
|
||||
screenCoords.x = (2 * x) / screenWidth - 1;
|
||||
screenCoords.y = (2 * y) / screenHeight - 1;
|
||||
screenCoords.z = (2 * screenCoords.z) - 1;
|
||||
screenCoords.project(this.inverseProjectionView);
|
||||
return screenCoords;
|
||||
}
|
||||
update() {
|
||||
let projection = this.projection;
|
||||
let view = this.view;
|
||||
let projectionView = this.projectionView;
|
||||
let inverseProjectionView = this.inverseProjectionView;
|
||||
let zoom = this.zoom, viewportWidth = this.viewportWidth, viewportHeight = this.viewportHeight;
|
||||
projection.ortho(zoom * (-viewportWidth / 2), zoom * (viewportWidth / 2),
|
||||
zoom * (-viewportHeight / 2), zoom * (viewportHeight / 2),
|
||||
this.near, this.far);
|
||||
view.lookAt(this.position, this.direction, this.up);
|
||||
projectionView.set(projection.values);
|
||||
projectionView.multiply(view);
|
||||
inverseProjectionView.set(projectionView.values).invert();
|
||||
}
|
||||
|
||||
worldToScreen (worldCoords: Vector3, screenWidth: number, screenHeight: number) {
|
||||
worldCoords.project(this.projectionView);
|
||||
worldCoords.x = screenWidth * (worldCoords.x + 1) / 2;
|
||||
worldCoords.y = screenHeight * (worldCoords.y + 1) / 2;
|
||||
worldCoords.z = (worldCoords.z + 1) / 2;
|
||||
return worldCoords;
|
||||
}
|
||||
screenToWorld(screenCoords: Vector3, screenWidth: number, screenHeight: number) {
|
||||
let x = screenCoords.x, y = screenHeight - screenCoords.y - 1;
|
||||
screenCoords.x = (2 * x) / screenWidth - 1;
|
||||
screenCoords.y = (2 * y) / screenHeight - 1;
|
||||
screenCoords.z = (2 * screenCoords.z) - 1;
|
||||
screenCoords.project(this.inverseProjectionView);
|
||||
return screenCoords;
|
||||
}
|
||||
|
||||
setViewport (viewportWidth: number, viewportHeight: number) {
|
||||
this.viewportWidth = viewportWidth;
|
||||
this.viewportHeight = viewportHeight;
|
||||
}
|
||||
worldToScreen(worldCoords: Vector3, screenWidth: number, screenHeight: number) {
|
||||
worldCoords.project(this.projectionView);
|
||||
worldCoords.x = screenWidth * (worldCoords.x + 1) / 2;
|
||||
worldCoords.y = screenHeight * (worldCoords.y + 1) / 2;
|
||||
worldCoords.z = (worldCoords.z + 1) / 2;
|
||||
return worldCoords;
|
||||
}
|
||||
|
||||
setViewport(viewportWidth: number, viewportHeight: number) {
|
||||
this.viewportWidth = viewportWidth;
|
||||
this.viewportHeight = viewportHeight;
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,85 +27,86 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
export class GLTexture extends Texture implements Disposable, Restorable {
|
||||
context: ManagedWebGLRenderingContext;
|
||||
private texture: WebGLTexture = null;
|
||||
private boundUnit = 0;
|
||||
private useMipMaps = false;
|
||||
import { Texture, Disposable, Restorable, TextureFilter, TextureWrap } from "spine-core";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL";
|
||||
|
||||
public static DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL = false;
|
||||
export class GLTexture extends Texture implements Disposable, Restorable {
|
||||
context: ManagedWebGLRenderingContext;
|
||||
private texture: WebGLTexture = null;
|
||||
private boundUnit = 0;
|
||||
private useMipMaps = false;
|
||||
|
||||
constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext, image: HTMLImageElement | ImageBitmap, useMipMaps: boolean = false) {
|
||||
super(image);
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
this.useMipMaps = useMipMaps;
|
||||
this.restore();
|
||||
this.context.addRestorable(this);
|
||||
}
|
||||
public static DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL = false;
|
||||
|
||||
setFilters (minFilter: TextureFilter, magFilter: TextureFilter) {
|
||||
let gl = this.context.gl;
|
||||
this.bind();
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, GLTexture.validateMagFilter(magFilter));
|
||||
}
|
||||
constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, image: HTMLImageElement | ImageBitmap, useMipMaps: boolean = false) {
|
||||
super(image);
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
this.useMipMaps = useMipMaps;
|
||||
this.restore();
|
||||
this.context.addRestorable(this);
|
||||
}
|
||||
|
||||
static validateMagFilter (magFilter: TextureFilter) {
|
||||
switch (magFilter) {
|
||||
case TextureFilter.MipMap:
|
||||
case TextureFilter.MipMapLinearLinear:
|
||||
case TextureFilter.MipMapLinearNearest:
|
||||
case TextureFilter.MipMapNearestLinear:
|
||||
case TextureFilter.MipMapNearestNearest:
|
||||
return TextureFilter.Linear;
|
||||
default:
|
||||
return magFilter;
|
||||
}
|
||||
}
|
||||
setFilters(minFilter: TextureFilter, magFilter: TextureFilter) {
|
||||
let gl = this.context.gl;
|
||||
this.bind();
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, GLTexture.validateMagFilter(magFilter));
|
||||
}
|
||||
|
||||
setWraps (uWrap: TextureWrap, vWrap: TextureWrap) {
|
||||
let gl = this.context.gl;
|
||||
this.bind();
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, uWrap);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, vWrap);
|
||||
}
|
||||
|
||||
update (useMipMaps: boolean) {
|
||||
let gl = this.context.gl;
|
||||
if (!this.texture) this.texture = this.context.gl.createTexture();
|
||||
this.bind();
|
||||
if (GLTexture.DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL) gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._image);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, useMipMaps ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
if (useMipMaps) gl.generateMipmap(gl.TEXTURE_2D);
|
||||
}
|
||||
|
||||
restore () {
|
||||
this.texture = null;
|
||||
this.update(this.useMipMaps);
|
||||
}
|
||||
|
||||
bind (unit: number = 0) {
|
||||
let gl = this.context.gl;
|
||||
this.boundUnit = unit;
|
||||
gl.activeTexture(gl.TEXTURE0 + unit);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
||||
}
|
||||
|
||||
unbind () {
|
||||
let gl = this.context.gl;
|
||||
gl.activeTexture(gl.TEXTURE0 + this.boundUnit);
|
||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
}
|
||||
|
||||
dispose () {
|
||||
this.context.removeRestorable(this);
|
||||
let gl = this.context.gl;
|
||||
gl.deleteTexture(this.texture);
|
||||
static validateMagFilter(magFilter: TextureFilter) {
|
||||
switch (magFilter) {
|
||||
case TextureFilter.MipMap:
|
||||
case TextureFilter.MipMapLinearLinear:
|
||||
case TextureFilter.MipMapLinearNearest:
|
||||
case TextureFilter.MipMapNearestLinear:
|
||||
case TextureFilter.MipMapNearestNearest:
|
||||
return TextureFilter.Linear;
|
||||
default:
|
||||
return magFilter;
|
||||
}
|
||||
}
|
||||
|
||||
setWraps(uWrap: TextureWrap, vWrap: TextureWrap) {
|
||||
let gl = this.context.gl;
|
||||
this.bind();
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, uWrap);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, vWrap);
|
||||
}
|
||||
|
||||
update(useMipMaps: boolean) {
|
||||
let gl = this.context.gl;
|
||||
if (!this.texture) this.texture = this.context.gl.createTexture();
|
||||
this.bind();
|
||||
if (GLTexture.DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL) gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._image);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, useMipMaps ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
if (useMipMaps) gl.generateMipmap(gl.TEXTURE_2D);
|
||||
}
|
||||
|
||||
restore() {
|
||||
this.texture = null;
|
||||
this.update(this.useMipMaps);
|
||||
}
|
||||
|
||||
bind(unit: number = 0) {
|
||||
let gl = this.context.gl;
|
||||
this.boundUnit = unit;
|
||||
gl.activeTexture(gl.TEXTURE0 + unit);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
||||
}
|
||||
|
||||
unbind() {
|
||||
let gl = this.context.gl;
|
||||
gl.activeTexture(gl.TEXTURE0 + this.boundUnit);
|
||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.context.removeRestorable(this);
|
||||
let gl = this.context.gl;
|
||||
gl.deleteTexture(this.texture);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,207 +27,207 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
export class Input {
|
||||
element: HTMLElement;
|
||||
lastX = 0;
|
||||
lastY = 0;
|
||||
buttonDown = false;
|
||||
currTouch: Touch = null;
|
||||
private listeners = new Array<InputListener>();
|
||||
import { Pool } from "spine-core";
|
||||
|
||||
touchesPool = new Pool<spine.webgl.Touch>(() => {
|
||||
return new spine.webgl.Touch(0, 0, 0);
|
||||
});
|
||||
export class Input {
|
||||
element: HTMLElement;
|
||||
lastX = 0;
|
||||
lastY = 0;
|
||||
buttonDown = false;
|
||||
currTouch: Touch = null;
|
||||
private listeners = new Array<InputListener>();
|
||||
|
||||
constructor (element: HTMLElement) {
|
||||
this.element = element;
|
||||
this.setupCallbacks(element);
|
||||
touchesPool = new Pool<Touch>(() => {
|
||||
return new spine.webgl.Touch(0, 0, 0);
|
||||
});
|
||||
|
||||
constructor(element: HTMLElement) {
|
||||
this.element = element;
|
||||
this.setupCallbacks(element);
|
||||
}
|
||||
|
||||
private setupCallbacks(element: HTMLElement) {
|
||||
let mouseDown = (ev: UIEvent) => {
|
||||
if (ev instanceof MouseEvent) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
let x = ev.clientX - rect.left;
|
||||
let y = ev.clientY - rect.top;
|
||||
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++)
|
||||
if (listeners[i].down) listeners[i].down(x, y);
|
||||
|
||||
this.lastX = x;
|
||||
this.lastY = y;
|
||||
this.buttonDown = true;
|
||||
|
||||
document.addEventListener("mousemove", mouseMove);
|
||||
document.addEventListener("mouseup", mouseUp);
|
||||
}
|
||||
}
|
||||
|
||||
private setupCallbacks (element: HTMLElement) {
|
||||
let mouseDown = (ev: UIEvent) => {
|
||||
if (ev instanceof MouseEvent) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
let x = ev.clientX - rect.left;
|
||||
let y = ev.clientY - rect.top;
|
||||
let mouseMove = (ev: UIEvent) => {
|
||||
if (ev instanceof MouseEvent) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
let x = ev.clientX - rect.left;
|
||||
let y = ev.clientY - rect.top;
|
||||
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++)
|
||||
if (listeners[i].down) listeners[i].down(x, y);
|
||||
|
||||
this.lastX = x;
|
||||
this.lastY = y;
|
||||
this.buttonDown = true;
|
||||
|
||||
document.addEventListener("mousemove", mouseMove);
|
||||
document.addEventListener("mouseup", mouseUp);
|
||||
}
|
||||
}
|
||||
|
||||
let mouseMove = (ev: UIEvent) => {
|
||||
if (ev instanceof MouseEvent) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
let x = ev.clientX - rect.left;
|
||||
let y = ev.clientY - rect.top;
|
||||
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
if (this.buttonDown) {
|
||||
if (listeners[i].dragged) listeners[i].dragged(x, y);
|
||||
} else {
|
||||
if (listeners[i].moved) listeners[i].moved(x, y);
|
||||
}
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
if (this.buttonDown) {
|
||||
if (listeners[i].dragged) listeners[i].dragged(x, y);
|
||||
} else {
|
||||
if (listeners[i].moved) listeners[i].moved(x, y);
|
||||
}
|
||||
|
||||
this.lastX = x;
|
||||
this.lastY = y;
|
||||
}
|
||||
};
|
||||
|
||||
let mouseUp = (ev: UIEvent) => {
|
||||
if (ev instanceof MouseEvent) {
|
||||
this.lastX = x;
|
||||
this.lastY = y;
|
||||
}
|
||||
};
|
||||
|
||||
let mouseUp = (ev: UIEvent) => {
|
||||
if (ev instanceof MouseEvent) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
let x = ev.clientX - rect.left;
|
||||
let y = ev.clientY - rect.top;
|
||||
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++)
|
||||
if (listeners[i].up) listeners[i].up(x, y);
|
||||
|
||||
this.lastX = x;
|
||||
this.lastY = y;
|
||||
this.buttonDown = false;
|
||||
document.removeEventListener("mousemove", mouseMove);
|
||||
document.removeEventListener("mouseup", mouseUp);
|
||||
}
|
||||
}
|
||||
|
||||
element.addEventListener("mousedown", mouseDown, true);
|
||||
element.addEventListener("mousemove", mouseMove, true);
|
||||
element.addEventListener("mouseup", mouseUp, true);
|
||||
element.addEventListener("touchstart", (ev: TouchEvent) => {
|
||||
if (!this.currTouch) {
|
||||
var touches = ev.changedTouches;
|
||||
for (var i = 0; i < touches.length; i++) {
|
||||
var touch = touches[i];
|
||||
let rect = element.getBoundingClientRect();
|
||||
let x = ev.clientX - rect.left;
|
||||
let y = ev.clientY - rect.top;
|
||||
let x = touch.clientX - rect.left;
|
||||
let y = touch.clientY - rect.top;
|
||||
this.currTouch = this.touchesPool.obtain();
|
||||
this.currTouch.identifier = touch.identifier;
|
||||
this.currTouch.x = x;
|
||||
this.currTouch.y = y;
|
||||
break;
|
||||
}
|
||||
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++)
|
||||
if (listeners[i].up) listeners[i].up(x, y);
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
if (listeners[i].down) listeners[i].down(this.currTouch.x, this.currTouch.y);
|
||||
}
|
||||
|
||||
this.lastX = x;
|
||||
this.lastY = y;
|
||||
this.buttonDown = false;
|
||||
document.removeEventListener("mousemove", mouseMove);
|
||||
document.removeEventListener("mouseup", mouseUp);
|
||||
this.lastX = this.currTouch.x;
|
||||
this.lastY = this.currTouch.y;
|
||||
this.buttonDown = true;
|
||||
}
|
||||
ev.preventDefault();
|
||||
}, false);
|
||||
element.addEventListener("touchend", (ev: TouchEvent) => {
|
||||
if (this.currTouch) {
|
||||
var touches = ev.changedTouches;
|
||||
for (var i = 0; i < touches.length; i++) {
|
||||
var touch = touches[i];
|
||||
if (this.currTouch.identifier === touch.identifier) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
let x = this.currTouch.x = touch.clientX - rect.left;
|
||||
let y = this.currTouch.y = touch.clientY - rect.top;
|
||||
this.touchesPool.free(this.currTouch);
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
if (listeners[i].up) listeners[i].up(x, y);
|
||||
}
|
||||
|
||||
this.lastX = x;
|
||||
this.lastY = y;
|
||||
this.buttonDown = false;
|
||||
this.currTouch = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ev.preventDefault();
|
||||
}, false);
|
||||
element.addEventListener("touchcancel", (ev: TouchEvent) => {
|
||||
if (this.currTouch) {
|
||||
var touches = ev.changedTouches;
|
||||
for (var i = 0; i < touches.length; i++) {
|
||||
var touch = touches[i];
|
||||
if (this.currTouch.identifier === touch.identifier) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
let x = this.currTouch.x = touch.clientX - rect.left;
|
||||
let y = this.currTouch.y = touch.clientY - rect.top;
|
||||
this.touchesPool.free(this.currTouch);
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
if (listeners[i].up) listeners[i].up(x, y);
|
||||
}
|
||||
|
||||
element.addEventListener("mousedown", mouseDown, true);
|
||||
element.addEventListener("mousemove", mouseMove, true);
|
||||
element.addEventListener("mouseup", mouseUp, true);
|
||||
element.addEventListener("touchstart", (ev: TouchEvent) => {
|
||||
if (!this.currTouch) {
|
||||
var touches = ev.changedTouches;
|
||||
for (var i = 0; i < touches.length; i++) {
|
||||
var touch = touches[i];
|
||||
this.lastX = x;
|
||||
this.lastY = y;
|
||||
this.buttonDown = false;
|
||||
this.currTouch = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ev.preventDefault();
|
||||
}, false);
|
||||
element.addEventListener("touchmove", (ev: TouchEvent) => {
|
||||
if (this.currTouch) {
|
||||
var touches = ev.changedTouches;
|
||||
for (var i = 0; i < touches.length; i++) {
|
||||
var touch = touches[i];
|
||||
if (this.currTouch.identifier === touch.identifier) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
let x = touch.clientX - rect.left;
|
||||
let y = touch.clientY - rect.top;
|
||||
this.currTouch = this.touchesPool.obtain();
|
||||
this.currTouch.identifier = touch.identifier;
|
||||
this.currTouch.x = x;
|
||||
this.currTouch.y = y;
|
||||
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
if (listeners[i].dragged) listeners[i].dragged(x, y);
|
||||
}
|
||||
|
||||
this.lastX = this.currTouch.x = x;
|
||||
this.lastY = this.currTouch.y = y;
|
||||
break;
|
||||
}
|
||||
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
if (listeners[i].down) listeners[i].down(this.currTouch.x, this.currTouch.y);
|
||||
}
|
||||
|
||||
this.lastX = this.currTouch.x;
|
||||
this.lastY = this.currTouch.y;
|
||||
this.buttonDown = true;
|
||||
}
|
||||
ev.preventDefault();
|
||||
}, false);
|
||||
element.addEventListener("touchend", (ev: TouchEvent) => {
|
||||
if (this.currTouch) {
|
||||
var touches = ev.changedTouches;
|
||||
for (var i = 0; i < touches.length; i++) {
|
||||
var touch = touches[i];
|
||||
if (this.currTouch.identifier === touch.identifier) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
let x = this.currTouch.x = touch.clientX - rect.left;
|
||||
let y = this.currTouch.y = touch.clientY - rect.top;
|
||||
this.touchesPool.free(this.currTouch);
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
if (listeners[i].up) listeners[i].up(x, y);
|
||||
}
|
||||
|
||||
this.lastX = x;
|
||||
this.lastY = y;
|
||||
this.buttonDown = false;
|
||||
this.currTouch = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ev.preventDefault();
|
||||
}, false);
|
||||
element.addEventListener("touchcancel", (ev: TouchEvent) => {
|
||||
if (this.currTouch) {
|
||||
var touches = ev.changedTouches;
|
||||
for (var i = 0; i < touches.length; i++) {
|
||||
var touch = touches[i];
|
||||
if (this.currTouch.identifier === touch.identifier) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
let x = this.currTouch.x = touch.clientX - rect.left;
|
||||
let y = this.currTouch.y = touch.clientY - rect.top;
|
||||
this.touchesPool.free(this.currTouch);
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
if (listeners[i].up) listeners[i].up(x, y);
|
||||
}
|
||||
|
||||
this.lastX = x;
|
||||
this.lastY = y;
|
||||
this.buttonDown = false;
|
||||
this.currTouch = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ev.preventDefault();
|
||||
}, false);
|
||||
element.addEventListener("touchmove", (ev: TouchEvent) => {
|
||||
if (this.currTouch) {
|
||||
var touches = ev.changedTouches;
|
||||
for (var i = 0; i < touches.length; i++) {
|
||||
var touch = touches[i];
|
||||
if (this.currTouch.identifier === touch.identifier) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
let x = touch.clientX - rect.left;
|
||||
let y = touch.clientY - rect.top;
|
||||
|
||||
let listeners = this.listeners;
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
if (listeners[i].dragged) listeners[i].dragged(x, y);
|
||||
}
|
||||
|
||||
this.lastX = this.currTouch.x = x;
|
||||
this.lastY = this.currTouch.y = y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ev.preventDefault();
|
||||
}, false);
|
||||
}
|
||||
|
||||
addListener (listener: InputListener) {
|
||||
this.listeners.push(listener);
|
||||
}
|
||||
|
||||
removeListener (listener: InputListener) {
|
||||
let idx = this.listeners.indexOf(listener);
|
||||
if (idx > -1) {
|
||||
this.listeners.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
ev.preventDefault();
|
||||
}, false);
|
||||
}
|
||||
|
||||
export class Touch {
|
||||
constructor (public identifier: number, public x: number, public y: number) {
|
||||
}
|
||||
addListener(listener: InputListener) {
|
||||
this.listeners.push(listener);
|
||||
}
|
||||
|
||||
export interface InputListener {
|
||||
down (x: number, y: number): void;
|
||||
up (x: number, y: number): void;
|
||||
moved (x: number, y: number): void;
|
||||
dragged (x: number, y: number): void;
|
||||
removeListener(listener: InputListener) {
|
||||
let idx = this.listeners.indexOf(listener);
|
||||
if (idx > -1) {
|
||||
this.listeners.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Touch {
|
||||
constructor(public identifier: number, public x: number, public y: number) {
|
||||
}
|
||||
}
|
||||
|
||||
export interface InputListener {
|
||||
down(x: number, y: number): void;
|
||||
up(x: number, y: number): void;
|
||||
moved(x: number, y: number): void;
|
||||
dragged(x: number, y: number): void;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -27,314 +27,314 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
export const M00 = 0;
|
||||
export const M01 = 4;
|
||||
export const M02 = 8;
|
||||
export const M03 = 12;
|
||||
export const M10 = 1;
|
||||
export const M11 = 5;
|
||||
export const M12 = 9;
|
||||
export const M13 = 13;
|
||||
export const M20 = 2;
|
||||
export const M21 = 6;
|
||||
export const M22 = 10;
|
||||
export const M23 = 14;
|
||||
export const M30 = 3;
|
||||
export const M31 = 7;
|
||||
export const M32 = 11;
|
||||
export const M33 = 15;
|
||||
import { Vector3 } from "./Vector3";
|
||||
|
||||
export class Matrix4 {
|
||||
temp: Float32Array = new Float32Array(16);
|
||||
values: Float32Array = new Float32Array(16);
|
||||
export const M00 = 0;
|
||||
export const M01 = 4;
|
||||
export const M02 = 8;
|
||||
export const M03 = 12;
|
||||
export const M10 = 1;
|
||||
export const M11 = 5;
|
||||
export const M12 = 9;
|
||||
export const M13 = 13;
|
||||
export const M20 = 2;
|
||||
export const M21 = 6;
|
||||
export const M22 = 10;
|
||||
export const M23 = 14;
|
||||
export const M30 = 3;
|
||||
export const M31 = 7;
|
||||
export const M32 = 11;
|
||||
export const M33 = 15;
|
||||
|
||||
private static xAxis: Vector3 = null;
|
||||
private static yAxis: Vector3 = null;
|
||||
private static zAxis: Vector3 = null;
|
||||
private static tmpMatrix = new Matrix4();
|
||||
export class Matrix4 {
|
||||
temp: Float32Array = new Float32Array(16);
|
||||
values: Float32Array = new Float32Array(16);
|
||||
|
||||
constructor () {
|
||||
let v = this.values;
|
||||
v[M00] = 1;
|
||||
v[M11] = 1;
|
||||
v[M22] = 1;
|
||||
v[M33] = 1;
|
||||
}
|
||||
private static xAxis: Vector3 = null;
|
||||
private static yAxis: Vector3 = null;
|
||||
private static zAxis: Vector3 = null;
|
||||
private static tmpMatrix = new Matrix4();
|
||||
|
||||
set (values: ArrayLike<number>): Matrix4 {
|
||||
this.values.set(values);
|
||||
return this;
|
||||
}
|
||||
constructor() {
|
||||
let v = this.values;
|
||||
v[M00] = 1;
|
||||
v[M11] = 1;
|
||||
v[M22] = 1;
|
||||
v[M33] = 1;
|
||||
}
|
||||
|
||||
transpose (): Matrix4 {
|
||||
let t = this.temp;
|
||||
let v = this.values;
|
||||
t[M00] = v[M00];
|
||||
t[M01] = v[M10];
|
||||
t[M02] = v[M20];
|
||||
t[M03] = v[M30];
|
||||
t[M10] = v[M01];
|
||||
t[M11] = v[M11];
|
||||
t[M12] = v[M21];
|
||||
t[M13] = v[M31];
|
||||
t[M20] = v[M02];
|
||||
t[M21] = v[M12];
|
||||
t[M22] = v[M22];
|
||||
t[M23] = v[M32];
|
||||
t[M30] = v[M03];
|
||||
t[M31] = v[M13];
|
||||
t[M32] = v[M23];
|
||||
t[M33] = v[M33];
|
||||
return this.set(t);
|
||||
}
|
||||
set(values: ArrayLike<number>): Matrix4 {
|
||||
this.values.set(values);
|
||||
return this;
|
||||
}
|
||||
|
||||
identity (): Matrix4 {
|
||||
let v = this.values;
|
||||
v[M00] = 1;
|
||||
v[M01] = 0;
|
||||
v[M02] = 0;
|
||||
v[M03] = 0;
|
||||
v[M10] = 0;
|
||||
v[M11] = 1;
|
||||
v[M12] = 0;
|
||||
v[M13] = 0;
|
||||
v[M20] = 0;
|
||||
v[M21] = 0;
|
||||
v[M22] = 1;
|
||||
v[M23] = 0;
|
||||
v[M30] = 0;
|
||||
v[M31] = 0;
|
||||
v[M32] = 0;
|
||||
v[M33] = 1;
|
||||
return this;
|
||||
}
|
||||
transpose(): Matrix4 {
|
||||
let t = this.temp;
|
||||
let v = this.values;
|
||||
t[M00] = v[M00];
|
||||
t[M01] = v[M10];
|
||||
t[M02] = v[M20];
|
||||
t[M03] = v[M30];
|
||||
t[M10] = v[M01];
|
||||
t[M11] = v[M11];
|
||||
t[M12] = v[M21];
|
||||
t[M13] = v[M31];
|
||||
t[M20] = v[M02];
|
||||
t[M21] = v[M12];
|
||||
t[M22] = v[M22];
|
||||
t[M23] = v[M32];
|
||||
t[M30] = v[M03];
|
||||
t[M31] = v[M13];
|
||||
t[M32] = v[M23];
|
||||
t[M33] = v[M33];
|
||||
return this.set(t);
|
||||
}
|
||||
|
||||
invert (): Matrix4 {
|
||||
let v = this.values;
|
||||
let t = this.temp;
|
||||
let l_det = v[M30] * v[M21] * v[M12] * v[M03] - v[M20] * v[M31] * v[M12] * v[M03] - v[M30] * v[M11] * v[M22] * v[M03]
|
||||
+ v[M10] * v[M31] * v[M22] * v[M03] + v[M20] * v[M11] * v[M32] * v[M03] - v[M10] * v[M21] * v[M32] * v[M03]
|
||||
- v[M30] * v[M21] * v[M02] * v[M13] + v[M20] * v[M31] * v[M02] * v[M13] + v[M30] * v[M01] * v[M22] * v[M13]
|
||||
- v[M00] * v[M31] * v[M22] * v[M13] - v[M20] * v[M01] * v[M32] * v[M13] + v[M00] * v[M21] * v[M32] * v[M13]
|
||||
+ v[M30] * v[M11] * v[M02] * v[M23] - v[M10] * v[M31] * v[M02] * v[M23] - v[M30] * v[M01] * v[M12] * v[M23]
|
||||
+ v[M00] * v[M31] * v[M12] * v[M23] + v[M10] * v[M01] * v[M32] * v[M23] - v[M00] * v[M11] * v[M32] * v[M23]
|
||||
- v[M20] * v[M11] * v[M02] * v[M33] + v[M10] * v[M21] * v[M02] * v[M33] + v[M20] * v[M01] * v[M12] * v[M33]
|
||||
- v[M00] * v[M21] * v[M12] * v[M33] - v[M10] * v[M01] * v[M22] * v[M33] + v[M00] * v[M11] * v[M22] * v[M33];
|
||||
if (l_det == 0) throw new Error("non-invertible matrix");
|
||||
let inv_det = 1.0 / l_det;
|
||||
t[M00] = v[M12] * v[M23] * v[M31] - v[M13] * v[M22] * v[M31] + v[M13] * v[M21] * v[M32]
|
||||
- v[M11] * v[M23] * v[M32] - v[M12] * v[M21] * v[M33] + v[M11] * v[M22] * v[M33];
|
||||
t[M01] = v[M03] * v[M22] * v[M31] - v[M02] * v[M23] * v[M31] - v[M03] * v[M21] * v[M32]
|
||||
+ v[M01] * v[M23] * v[M32] + v[M02] * v[M21] * v[M33] - v[M01] * v[M22] * v[M33];
|
||||
t[M02] = v[M02] * v[M13] * v[M31] - v[M03] * v[M12] * v[M31] + v[M03] * v[M11] * v[M32]
|
||||
- v[M01] * v[M13] * v[M32] - v[M02] * v[M11] * v[M33] + v[M01] * v[M12] * v[M33];
|
||||
t[M03] = v[M03] * v[M12] * v[M21] - v[M02] * v[M13] * v[M21] - v[M03] * v[M11] * v[M22]
|
||||
+ v[M01] * v[M13] * v[M22] + v[M02] * v[M11] * v[M23] - v[M01] * v[M12] * v[M23];
|
||||
t[M10] = v[M13] * v[M22] * v[M30] - v[M12] * v[M23] * v[M30] - v[M13] * v[M20] * v[M32]
|
||||
+ v[M10] * v[M23] * v[M32] + v[M12] * v[M20] * v[M33] - v[M10] * v[M22] * v[M33];
|
||||
t[M11] = v[M02] * v[M23] * v[M30] - v[M03] * v[M22] * v[M30] + v[M03] * v[M20] * v[M32]
|
||||
- v[M00] * v[M23] * v[M32] - v[M02] * v[M20] * v[M33] + v[M00] * v[M22] * v[M33];
|
||||
t[M12] = v[M03] * v[M12] * v[M30] - v[M02] * v[M13] * v[M30] - v[M03] * v[M10] * v[M32]
|
||||
+ v[M00] * v[M13] * v[M32] + v[M02] * v[M10] * v[M33] - v[M00] * v[M12] * v[M33];
|
||||
t[M13] = v[M02] * v[M13] * v[M20] - v[M03] * v[M12] * v[M20] + v[M03] * v[M10] * v[M22]
|
||||
- v[M00] * v[M13] * v[M22] - v[M02] * v[M10] * v[M23] + v[M00] * v[M12] * v[M23];
|
||||
t[M20] = v[M11] * v[M23] * v[M30] - v[M13] * v[M21] * v[M30] + v[M13] * v[M20] * v[M31]
|
||||
- v[M10] * v[M23] * v[M31] - v[M11] * v[M20] * v[M33] + v[M10] * v[M21] * v[M33];
|
||||
t[M21] = v[M03] * v[M21] * v[M30] - v[M01] * v[M23] * v[M30] - v[M03] * v[M20] * v[M31]
|
||||
+ v[M00] * v[M23] * v[M31] + v[M01] * v[M20] * v[M33] - v[M00] * v[M21] * v[M33];
|
||||
t[M22] = v[M01] * v[M13] * v[M30] - v[M03] * v[M11] * v[M30] + v[M03] * v[M10] * v[M31]
|
||||
- v[M00] * v[M13] * v[M31] - v[M01] * v[M10] * v[M33] + v[M00] * v[M11] * v[M33];
|
||||
t[M23] = v[M03] * v[M11] * v[M20] - v[M01] * v[M13] * v[M20] - v[M03] * v[M10] * v[M21]
|
||||
+ v[M00] * v[M13] * v[M21] + v[M01] * v[M10] * v[M23] - v[M00] * v[M11] * v[M23];
|
||||
t[M30] = v[M12] * v[M21] * v[M30] - v[M11] * v[M22] * v[M30] - v[M12] * v[M20] * v[M31]
|
||||
+ v[M10] * v[M22] * v[M31] + v[M11] * v[M20] * v[M32] - v[M10] * v[M21] * v[M32];
|
||||
t[M31] = v[M01] * v[M22] * v[M30] - v[M02] * v[M21] * v[M30] + v[M02] * v[M20] * v[M31]
|
||||
- v[M00] * v[M22] * v[M31] - v[M01] * v[M20] * v[M32] + v[M00] * v[M21] * v[M32];
|
||||
t[M32] = v[M02] * v[M11] * v[M30] - v[M01] * v[M12] * v[M30] - v[M02] * v[M10] * v[M31]
|
||||
+ v[M00] * v[M12] * v[M31] + v[M01] * v[M10] * v[M32] - v[M00] * v[M11] * v[M32];
|
||||
t[M33] = v[M01] * v[M12] * v[M20] - v[M02] * v[M11] * v[M20] + v[M02] * v[M10] * v[M21]
|
||||
- v[M00] * v[M12] * v[M21] - v[M01] * v[M10] * v[M22] + v[M00] * v[M11] * v[M22];
|
||||
v[M00] = t[M00] * inv_det;
|
||||
v[M01] = t[M01] * inv_det;
|
||||
v[M02] = t[M02] * inv_det;
|
||||
v[M03] = t[M03] * inv_det;
|
||||
v[M10] = t[M10] * inv_det;
|
||||
v[M11] = t[M11] * inv_det;
|
||||
v[M12] = t[M12] * inv_det;
|
||||
v[M13] = t[M13] * inv_det;
|
||||
v[M20] = t[M20] * inv_det;
|
||||
v[M21] = t[M21] * inv_det;
|
||||
v[M22] = t[M22] * inv_det;
|
||||
v[M23] = t[M23] * inv_det;
|
||||
v[M30] = t[M30] * inv_det;
|
||||
v[M31] = t[M31] * inv_det;
|
||||
v[M32] = t[M32] * inv_det;
|
||||
v[M33] = t[M33] * inv_det;
|
||||
return this;
|
||||
}
|
||||
identity(): Matrix4 {
|
||||
let v = this.values;
|
||||
v[M00] = 1;
|
||||
v[M01] = 0;
|
||||
v[M02] = 0;
|
||||
v[M03] = 0;
|
||||
v[M10] = 0;
|
||||
v[M11] = 1;
|
||||
v[M12] = 0;
|
||||
v[M13] = 0;
|
||||
v[M20] = 0;
|
||||
v[M21] = 0;
|
||||
v[M22] = 1;
|
||||
v[M23] = 0;
|
||||
v[M30] = 0;
|
||||
v[M31] = 0;
|
||||
v[M32] = 0;
|
||||
v[M33] = 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
determinant (): number {
|
||||
let v = this.values;
|
||||
return v[M30] * v[M21] * v[M12] * v[M03] - v[M20] * v[M31] * v[M12] * v[M03] - v[M30] * v[M11] * v[M22] * v[M03]
|
||||
+ v[M10] * v[M31] * v[M22] * v[M03] + v[M20] * v[M11] * v[M32] * v[M03] - v[M10] * v[M21] * v[M32] * v[M03]
|
||||
- v[M30] * v[M21] * v[M02] * v[M13] + v[M20] * v[M31] * v[M02] * v[M13] + v[M30] * v[M01] * v[M22] * v[M13]
|
||||
- v[M00] * v[M31] * v[M22] * v[M13] - v[M20] * v[M01] * v[M32] * v[M13] + v[M00] * v[M21] * v[M32] * v[M13]
|
||||
+ v[M30] * v[M11] * v[M02] * v[M23] - v[M10] * v[M31] * v[M02] * v[M23] - v[M30] * v[M01] * v[M12] * v[M23]
|
||||
+ v[M00] * v[M31] * v[M12] * v[M23] + v[M10] * v[M01] * v[M32] * v[M23] - v[M00] * v[M11] * v[M32] * v[M23]
|
||||
- v[M20] * v[M11] * v[M02] * v[M33] + v[M10] * v[M21] * v[M02] * v[M33] + v[M20] * v[M01] * v[M12] * v[M33]
|
||||
- v[M00] * v[M21] * v[M12] * v[M33] - v[M10] * v[M01] * v[M22] * v[M33] + v[M00] * v[M11] * v[M22] * v[M33];
|
||||
}
|
||||
invert(): Matrix4 {
|
||||
let v = this.values;
|
||||
let t = this.temp;
|
||||
let l_det = v[M30] * v[M21] * v[M12] * v[M03] - v[M20] * v[M31] * v[M12] * v[M03] - v[M30] * v[M11] * v[M22] * v[M03]
|
||||
+ v[M10] * v[M31] * v[M22] * v[M03] + v[M20] * v[M11] * v[M32] * v[M03] - v[M10] * v[M21] * v[M32] * v[M03]
|
||||
- v[M30] * v[M21] * v[M02] * v[M13] + v[M20] * v[M31] * v[M02] * v[M13] + v[M30] * v[M01] * v[M22] * v[M13]
|
||||
- v[M00] * v[M31] * v[M22] * v[M13] - v[M20] * v[M01] * v[M32] * v[M13] + v[M00] * v[M21] * v[M32] * v[M13]
|
||||
+ v[M30] * v[M11] * v[M02] * v[M23] - v[M10] * v[M31] * v[M02] * v[M23] - v[M30] * v[M01] * v[M12] * v[M23]
|
||||
+ v[M00] * v[M31] * v[M12] * v[M23] + v[M10] * v[M01] * v[M32] * v[M23] - v[M00] * v[M11] * v[M32] * v[M23]
|
||||
- v[M20] * v[M11] * v[M02] * v[M33] + v[M10] * v[M21] * v[M02] * v[M33] + v[M20] * v[M01] * v[M12] * v[M33]
|
||||
- v[M00] * v[M21] * v[M12] * v[M33] - v[M10] * v[M01] * v[M22] * v[M33] + v[M00] * v[M11] * v[M22] * v[M33];
|
||||
if (l_det == 0) throw new Error("non-invertible matrix");
|
||||
let inv_det = 1.0 / l_det;
|
||||
t[M00] = v[M12] * v[M23] * v[M31] - v[M13] * v[M22] * v[M31] + v[M13] * v[M21] * v[M32]
|
||||
- v[M11] * v[M23] * v[M32] - v[M12] * v[M21] * v[M33] + v[M11] * v[M22] * v[M33];
|
||||
t[M01] = v[M03] * v[M22] * v[M31] - v[M02] * v[M23] * v[M31] - v[M03] * v[M21] * v[M32]
|
||||
+ v[M01] * v[M23] * v[M32] + v[M02] * v[M21] * v[M33] - v[M01] * v[M22] * v[M33];
|
||||
t[M02] = v[M02] * v[M13] * v[M31] - v[M03] * v[M12] * v[M31] + v[M03] * v[M11] * v[M32]
|
||||
- v[M01] * v[M13] * v[M32] - v[M02] * v[M11] * v[M33] + v[M01] * v[M12] * v[M33];
|
||||
t[M03] = v[M03] * v[M12] * v[M21] - v[M02] * v[M13] * v[M21] - v[M03] * v[M11] * v[M22]
|
||||
+ v[M01] * v[M13] * v[M22] + v[M02] * v[M11] * v[M23] - v[M01] * v[M12] * v[M23];
|
||||
t[M10] = v[M13] * v[M22] * v[M30] - v[M12] * v[M23] * v[M30] - v[M13] * v[M20] * v[M32]
|
||||
+ v[M10] * v[M23] * v[M32] + v[M12] * v[M20] * v[M33] - v[M10] * v[M22] * v[M33];
|
||||
t[M11] = v[M02] * v[M23] * v[M30] - v[M03] * v[M22] * v[M30] + v[M03] * v[M20] * v[M32]
|
||||
- v[M00] * v[M23] * v[M32] - v[M02] * v[M20] * v[M33] + v[M00] * v[M22] * v[M33];
|
||||
t[M12] = v[M03] * v[M12] * v[M30] - v[M02] * v[M13] * v[M30] - v[M03] * v[M10] * v[M32]
|
||||
+ v[M00] * v[M13] * v[M32] + v[M02] * v[M10] * v[M33] - v[M00] * v[M12] * v[M33];
|
||||
t[M13] = v[M02] * v[M13] * v[M20] - v[M03] * v[M12] * v[M20] + v[M03] * v[M10] * v[M22]
|
||||
- v[M00] * v[M13] * v[M22] - v[M02] * v[M10] * v[M23] + v[M00] * v[M12] * v[M23];
|
||||
t[M20] = v[M11] * v[M23] * v[M30] - v[M13] * v[M21] * v[M30] + v[M13] * v[M20] * v[M31]
|
||||
- v[M10] * v[M23] * v[M31] - v[M11] * v[M20] * v[M33] + v[M10] * v[M21] * v[M33];
|
||||
t[M21] = v[M03] * v[M21] * v[M30] - v[M01] * v[M23] * v[M30] - v[M03] * v[M20] * v[M31]
|
||||
+ v[M00] * v[M23] * v[M31] + v[M01] * v[M20] * v[M33] - v[M00] * v[M21] * v[M33];
|
||||
t[M22] = v[M01] * v[M13] * v[M30] - v[M03] * v[M11] * v[M30] + v[M03] * v[M10] * v[M31]
|
||||
- v[M00] * v[M13] * v[M31] - v[M01] * v[M10] * v[M33] + v[M00] * v[M11] * v[M33];
|
||||
t[M23] = v[M03] * v[M11] * v[M20] - v[M01] * v[M13] * v[M20] - v[M03] * v[M10] * v[M21]
|
||||
+ v[M00] * v[M13] * v[M21] + v[M01] * v[M10] * v[M23] - v[M00] * v[M11] * v[M23];
|
||||
t[M30] = v[M12] * v[M21] * v[M30] - v[M11] * v[M22] * v[M30] - v[M12] * v[M20] * v[M31]
|
||||
+ v[M10] * v[M22] * v[M31] + v[M11] * v[M20] * v[M32] - v[M10] * v[M21] * v[M32];
|
||||
t[M31] = v[M01] * v[M22] * v[M30] - v[M02] * v[M21] * v[M30] + v[M02] * v[M20] * v[M31]
|
||||
- v[M00] * v[M22] * v[M31] - v[M01] * v[M20] * v[M32] + v[M00] * v[M21] * v[M32];
|
||||
t[M32] = v[M02] * v[M11] * v[M30] - v[M01] * v[M12] * v[M30] - v[M02] * v[M10] * v[M31]
|
||||
+ v[M00] * v[M12] * v[M31] + v[M01] * v[M10] * v[M32] - v[M00] * v[M11] * v[M32];
|
||||
t[M33] = v[M01] * v[M12] * v[M20] - v[M02] * v[M11] * v[M20] + v[M02] * v[M10] * v[M21]
|
||||
- v[M00] * v[M12] * v[M21] - v[M01] * v[M10] * v[M22] + v[M00] * v[M11] * v[M22];
|
||||
v[M00] = t[M00] * inv_det;
|
||||
v[M01] = t[M01] * inv_det;
|
||||
v[M02] = t[M02] * inv_det;
|
||||
v[M03] = t[M03] * inv_det;
|
||||
v[M10] = t[M10] * inv_det;
|
||||
v[M11] = t[M11] * inv_det;
|
||||
v[M12] = t[M12] * inv_det;
|
||||
v[M13] = t[M13] * inv_det;
|
||||
v[M20] = t[M20] * inv_det;
|
||||
v[M21] = t[M21] * inv_det;
|
||||
v[M22] = t[M22] * inv_det;
|
||||
v[M23] = t[M23] * inv_det;
|
||||
v[M30] = t[M30] * inv_det;
|
||||
v[M31] = t[M31] * inv_det;
|
||||
v[M32] = t[M32] * inv_det;
|
||||
v[M33] = t[M33] * inv_det;
|
||||
return this;
|
||||
}
|
||||
|
||||
translate (x: number, y: number, z: number): Matrix4 {
|
||||
let v = this.values;
|
||||
v[M03] += x;
|
||||
v[M13] += y;
|
||||
v[M23] += z;
|
||||
return this;
|
||||
}
|
||||
determinant(): number {
|
||||
let v = this.values;
|
||||
return v[M30] * v[M21] * v[M12] * v[M03] - v[M20] * v[M31] * v[M12] * v[M03] - v[M30] * v[M11] * v[M22] * v[M03]
|
||||
+ v[M10] * v[M31] * v[M22] * v[M03] + v[M20] * v[M11] * v[M32] * v[M03] - v[M10] * v[M21] * v[M32] * v[M03]
|
||||
- v[M30] * v[M21] * v[M02] * v[M13] + v[M20] * v[M31] * v[M02] * v[M13] + v[M30] * v[M01] * v[M22] * v[M13]
|
||||
- v[M00] * v[M31] * v[M22] * v[M13] - v[M20] * v[M01] * v[M32] * v[M13] + v[M00] * v[M21] * v[M32] * v[M13]
|
||||
+ v[M30] * v[M11] * v[M02] * v[M23] - v[M10] * v[M31] * v[M02] * v[M23] - v[M30] * v[M01] * v[M12] * v[M23]
|
||||
+ v[M00] * v[M31] * v[M12] * v[M23] + v[M10] * v[M01] * v[M32] * v[M23] - v[M00] * v[M11] * v[M32] * v[M23]
|
||||
- v[M20] * v[M11] * v[M02] * v[M33] + v[M10] * v[M21] * v[M02] * v[M33] + v[M20] * v[M01] * v[M12] * v[M33]
|
||||
- v[M00] * v[M21] * v[M12] * v[M33] - v[M10] * v[M01] * v[M22] * v[M33] + v[M00] * v[M11] * v[M22] * v[M33];
|
||||
}
|
||||
|
||||
copy (): Matrix4 {
|
||||
return new Matrix4().set(this.values);
|
||||
}
|
||||
translate(x: number, y: number, z: number): Matrix4 {
|
||||
let v = this.values;
|
||||
v[M03] += x;
|
||||
v[M13] += y;
|
||||
v[M23] += z;
|
||||
return this;
|
||||
}
|
||||
|
||||
projection (near: number, far: number, fovy: number, aspectRatio: number): Matrix4 {
|
||||
this.identity();
|
||||
let l_fd = (1.0 / Math.tan((fovy * (Math.PI / 180)) / 2.0));
|
||||
let l_a1 = (far + near) / (near - far);
|
||||
let l_a2 = (2 * far * near) / (near - far);
|
||||
let v = this.values;
|
||||
v[M00] = l_fd / aspectRatio;
|
||||
v[M10] = 0;
|
||||
v[M20] = 0;
|
||||
v[M30] = 0;
|
||||
v[M01] = 0;
|
||||
v[M11] = l_fd;
|
||||
v[M21] = 0;
|
||||
v[M31] = 0;
|
||||
v[M02] = 0;
|
||||
v[M12] = 0;
|
||||
v[M22] = l_a1;
|
||||
v[M32] = -1;
|
||||
v[M03] = 0;
|
||||
v[M13] = 0;
|
||||
v[M23] = l_a2;
|
||||
v[M33] = 0;
|
||||
return this;
|
||||
}
|
||||
copy(): Matrix4 {
|
||||
return new Matrix4().set(this.values);
|
||||
}
|
||||
|
||||
ortho2d (x: number, y: number, width: number, height: number): Matrix4 {
|
||||
return this.ortho(x, x + width, y, y + height, 0, 1);
|
||||
}
|
||||
projection(near: number, far: number, fovy: number, aspectRatio: number): Matrix4 {
|
||||
this.identity();
|
||||
let l_fd = (1.0 / Math.tan((fovy * (Math.PI / 180)) / 2.0));
|
||||
let l_a1 = (far + near) / (near - far);
|
||||
let l_a2 = (2 * far * near) / (near - far);
|
||||
let v = this.values;
|
||||
v[M00] = l_fd / aspectRatio;
|
||||
v[M10] = 0;
|
||||
v[M20] = 0;
|
||||
v[M30] = 0;
|
||||
v[M01] = 0;
|
||||
v[M11] = l_fd;
|
||||
v[M21] = 0;
|
||||
v[M31] = 0;
|
||||
v[M02] = 0;
|
||||
v[M12] = 0;
|
||||
v[M22] = l_a1;
|
||||
v[M32] = -1;
|
||||
v[M03] = 0;
|
||||
v[M13] = 0;
|
||||
v[M23] = l_a2;
|
||||
v[M33] = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
ortho (left: number, right: number, bottom: number, top: number, near: number, far: number): Matrix4 {
|
||||
this.identity();
|
||||
let x_orth = 2 / (right - left);
|
||||
let y_orth = 2 / (top - bottom);
|
||||
let z_orth = -2 / (far - near);
|
||||
ortho2d(x: number, y: number, width: number, height: number): Matrix4 {
|
||||
return this.ortho(x, x + width, y, y + height, 0, 1);
|
||||
}
|
||||
|
||||
let tx = -(right + left) / (right - left);
|
||||
let ty = -(top + bottom) / (top - bottom);
|
||||
let tz = -(far + near) / (far - near);
|
||||
ortho(left: number, right: number, bottom: number, top: number, near: number, far: number): Matrix4 {
|
||||
this.identity();
|
||||
let x_orth = 2 / (right - left);
|
||||
let y_orth = 2 / (top - bottom);
|
||||
let z_orth = -2 / (far - near);
|
||||
|
||||
let v = this.values;
|
||||
v[M00] = x_orth;
|
||||
v[M10] = 0;
|
||||
v[M20] = 0;
|
||||
v[M30] = 0;
|
||||
v[M01] = 0;
|
||||
v[M11] = y_orth;
|
||||
v[M21] = 0;
|
||||
v[M31] = 0;
|
||||
v[M02] = 0;
|
||||
v[M12] = 0;
|
||||
v[M22] = z_orth;
|
||||
v[M32] = 0;
|
||||
v[M03] = tx;
|
||||
v[M13] = ty;
|
||||
v[M23] = tz;
|
||||
v[M33] = 1;
|
||||
return this;
|
||||
}
|
||||
let tx = -(right + left) / (right - left);
|
||||
let ty = -(top + bottom) / (top - bottom);
|
||||
let tz = -(far + near) / (far - near);
|
||||
|
||||
multiply (matrix: Matrix4): Matrix4 {
|
||||
let t = this.temp;
|
||||
let v = this.values;
|
||||
let m = matrix.values;
|
||||
t[M00] = v[M00] * m[M00] + v[M01] * m[M10] + v[M02] * m[M20] + v[M03] * m[M30];
|
||||
t[M01] = v[M00] * m[M01] + v[M01] * m[M11] + v[M02] * m[M21] + v[M03] * m[M31];
|
||||
t[M02] = v[M00] * m[M02] + v[M01] * m[M12] + v[M02] * m[M22] + v[M03] * m[M32];
|
||||
t[M03] = v[M00] * m[M03] + v[M01] * m[M13] + v[M02] * m[M23] + v[M03] * m[M33];
|
||||
t[M10] = v[M10] * m[M00] + v[M11] * m[M10] + v[M12] * m[M20] + v[M13] * m[M30];
|
||||
t[M11] = v[M10] * m[M01] + v[M11] * m[M11] + v[M12] * m[M21] + v[M13] * m[M31];
|
||||
t[M12] = v[M10] * m[M02] + v[M11] * m[M12] + v[M12] * m[M22] + v[M13] * m[M32];
|
||||
t[M13] = v[M10] * m[M03] + v[M11] * m[M13] + v[M12] * m[M23] + v[M13] * m[M33];
|
||||
t[M20] = v[M20] * m[M00] + v[M21] * m[M10] + v[M22] * m[M20] + v[M23] * m[M30];
|
||||
t[M21] = v[M20] * m[M01] + v[M21] * m[M11] + v[M22] * m[M21] + v[M23] * m[M31];
|
||||
t[M22] = v[M20] * m[M02] + v[M21] * m[M12] + v[M22] * m[M22] + v[M23] * m[M32];
|
||||
t[M23] = v[M20] * m[M03] + v[M21] * m[M13] + v[M22] * m[M23] + v[M23] * m[M33];
|
||||
t[M30] = v[M30] * m[M00] + v[M31] * m[M10] + v[M32] * m[M20] + v[M33] * m[M30];
|
||||
t[M31] = v[M30] * m[M01] + v[M31] * m[M11] + v[M32] * m[M21] + v[M33] * m[M31];
|
||||
t[M32] = v[M30] * m[M02] + v[M31] * m[M12] + v[M32] * m[M22] + v[M33] * m[M32];
|
||||
t[M33] = v[M30] * m[M03] + v[M31] * m[M13] + v[M32] * m[M23] + v[M33] * m[M33];
|
||||
return this.set(this.temp);
|
||||
}
|
||||
let v = this.values;
|
||||
v[M00] = x_orth;
|
||||
v[M10] = 0;
|
||||
v[M20] = 0;
|
||||
v[M30] = 0;
|
||||
v[M01] = 0;
|
||||
v[M11] = y_orth;
|
||||
v[M21] = 0;
|
||||
v[M31] = 0;
|
||||
v[M02] = 0;
|
||||
v[M12] = 0;
|
||||
v[M22] = z_orth;
|
||||
v[M32] = 0;
|
||||
v[M03] = tx;
|
||||
v[M13] = ty;
|
||||
v[M23] = tz;
|
||||
v[M33] = 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
multiplyLeft (matrix: Matrix4): Matrix4 {
|
||||
let t = this.temp;
|
||||
let v = this.values;
|
||||
let m = matrix.values;
|
||||
t[M00] = m[M00] * v[M00] + m[M01] * v[M10] + m[M02] * v[M20] + m[M03] * v[M30];
|
||||
t[M01] = m[M00] * v[M01] + m[M01] * v[M11] + m[M02] * v[M21] + m[M03] * v[M31];
|
||||
t[M02] = m[M00] * v[M02] + m[M01] * v[M12] + m[M02] * v[M22] + m[M03] * v[M32];
|
||||
t[M03] = m[M00] * v[M03] + m[M01] * v[M13] + m[M02] * v[M23] + m[M03] * v[M33];
|
||||
t[M10] = m[M10] * v[M00] + m[M11] * v[M10] + m[M12] * v[M20] + m[M13] * v[M30];
|
||||
t[M11] = m[M10] * v[M01] + m[M11] * v[M11] + m[M12] * v[M21] + m[M13] * v[M31];
|
||||
t[M12] = m[M10] * v[M02] + m[M11] * v[M12] + m[M12] * v[M22] + m[M13] * v[M32];
|
||||
t[M13] = m[M10] * v[M03] + m[M11] * v[M13] + m[M12] * v[M23] + m[M13] * v[M33];
|
||||
t[M20] = m[M20] * v[M00] + m[M21] * v[M10] + m[M22] * v[M20] + m[M23] * v[M30];
|
||||
t[M21] = m[M20] * v[M01] + m[M21] * v[M11] + m[M22] * v[M21] + m[M23] * v[M31];
|
||||
t[M22] = m[M20] * v[M02] + m[M21] * v[M12] + m[M22] * v[M22] + m[M23] * v[M32];
|
||||
t[M23] = m[M20] * v[M03] + m[M21] * v[M13] + m[M22] * v[M23] + m[M23] * v[M33];
|
||||
t[M30] = m[M30] * v[M00] + m[M31] * v[M10] + m[M32] * v[M20] + m[M33] * v[M30];
|
||||
t[M31] = m[M30] * v[M01] + m[M31] * v[M11] + m[M32] * v[M21] + m[M33] * v[M31];
|
||||
t[M32] = m[M30] * v[M02] + m[M31] * v[M12] + m[M32] * v[M22] + m[M33] * v[M32];
|
||||
t[M33] = m[M30] * v[M03] + m[M31] * v[M13] + m[M32] * v[M23] + m[M33] * v[M33];
|
||||
return this.set(this.temp);
|
||||
}
|
||||
multiply(matrix: Matrix4): Matrix4 {
|
||||
let t = this.temp;
|
||||
let v = this.values;
|
||||
let m = matrix.values;
|
||||
t[M00] = v[M00] * m[M00] + v[M01] * m[M10] + v[M02] * m[M20] + v[M03] * m[M30];
|
||||
t[M01] = v[M00] * m[M01] + v[M01] * m[M11] + v[M02] * m[M21] + v[M03] * m[M31];
|
||||
t[M02] = v[M00] * m[M02] + v[M01] * m[M12] + v[M02] * m[M22] + v[M03] * m[M32];
|
||||
t[M03] = v[M00] * m[M03] + v[M01] * m[M13] + v[M02] * m[M23] + v[M03] * m[M33];
|
||||
t[M10] = v[M10] * m[M00] + v[M11] * m[M10] + v[M12] * m[M20] + v[M13] * m[M30];
|
||||
t[M11] = v[M10] * m[M01] + v[M11] * m[M11] + v[M12] * m[M21] + v[M13] * m[M31];
|
||||
t[M12] = v[M10] * m[M02] + v[M11] * m[M12] + v[M12] * m[M22] + v[M13] * m[M32];
|
||||
t[M13] = v[M10] * m[M03] + v[M11] * m[M13] + v[M12] * m[M23] + v[M13] * m[M33];
|
||||
t[M20] = v[M20] * m[M00] + v[M21] * m[M10] + v[M22] * m[M20] + v[M23] * m[M30];
|
||||
t[M21] = v[M20] * m[M01] + v[M21] * m[M11] + v[M22] * m[M21] + v[M23] * m[M31];
|
||||
t[M22] = v[M20] * m[M02] + v[M21] * m[M12] + v[M22] * m[M22] + v[M23] * m[M32];
|
||||
t[M23] = v[M20] * m[M03] + v[M21] * m[M13] + v[M22] * m[M23] + v[M23] * m[M33];
|
||||
t[M30] = v[M30] * m[M00] + v[M31] * m[M10] + v[M32] * m[M20] + v[M33] * m[M30];
|
||||
t[M31] = v[M30] * m[M01] + v[M31] * m[M11] + v[M32] * m[M21] + v[M33] * m[M31];
|
||||
t[M32] = v[M30] * m[M02] + v[M31] * m[M12] + v[M32] * m[M22] + v[M33] * m[M32];
|
||||
t[M33] = v[M30] * m[M03] + v[M31] * m[M13] + v[M32] * m[M23] + v[M33] * m[M33];
|
||||
return this.set(this.temp);
|
||||
}
|
||||
|
||||
lookAt (position: Vector3, direction: Vector3, up: Vector3) {
|
||||
Matrix4.initTemps();
|
||||
let xAxis = Matrix4.xAxis, yAxis = Matrix4.yAxis, zAxis = Matrix4.zAxis;
|
||||
zAxis.setFrom(direction).normalize();
|
||||
xAxis.setFrom(direction).normalize();
|
||||
xAxis.cross(up).normalize();
|
||||
yAxis.setFrom(xAxis).cross(zAxis).normalize();
|
||||
this.identity();
|
||||
let val = this.values;
|
||||
val[M00] = xAxis.x;
|
||||
val[M01] = xAxis.y;
|
||||
val[M02] = xAxis.z;
|
||||
val[M10] = yAxis.x;
|
||||
val[M11] = yAxis.y;
|
||||
val[M12] = yAxis.z;
|
||||
val[M20] = -zAxis.x;
|
||||
val[M21] = -zAxis.y;
|
||||
val[M22] = -zAxis.z;
|
||||
multiplyLeft(matrix: Matrix4): Matrix4 {
|
||||
let t = this.temp;
|
||||
let v = this.values;
|
||||
let m = matrix.values;
|
||||
t[M00] = m[M00] * v[M00] + m[M01] * v[M10] + m[M02] * v[M20] + m[M03] * v[M30];
|
||||
t[M01] = m[M00] * v[M01] + m[M01] * v[M11] + m[M02] * v[M21] + m[M03] * v[M31];
|
||||
t[M02] = m[M00] * v[M02] + m[M01] * v[M12] + m[M02] * v[M22] + m[M03] * v[M32];
|
||||
t[M03] = m[M00] * v[M03] + m[M01] * v[M13] + m[M02] * v[M23] + m[M03] * v[M33];
|
||||
t[M10] = m[M10] * v[M00] + m[M11] * v[M10] + m[M12] * v[M20] + m[M13] * v[M30];
|
||||
t[M11] = m[M10] * v[M01] + m[M11] * v[M11] + m[M12] * v[M21] + m[M13] * v[M31];
|
||||
t[M12] = m[M10] * v[M02] + m[M11] * v[M12] + m[M12] * v[M22] + m[M13] * v[M32];
|
||||
t[M13] = m[M10] * v[M03] + m[M11] * v[M13] + m[M12] * v[M23] + m[M13] * v[M33];
|
||||
t[M20] = m[M20] * v[M00] + m[M21] * v[M10] + m[M22] * v[M20] + m[M23] * v[M30];
|
||||
t[M21] = m[M20] * v[M01] + m[M21] * v[M11] + m[M22] * v[M21] + m[M23] * v[M31];
|
||||
t[M22] = m[M20] * v[M02] + m[M21] * v[M12] + m[M22] * v[M22] + m[M23] * v[M32];
|
||||
t[M23] = m[M20] * v[M03] + m[M21] * v[M13] + m[M22] * v[M23] + m[M23] * v[M33];
|
||||
t[M30] = m[M30] * v[M00] + m[M31] * v[M10] + m[M32] * v[M20] + m[M33] * v[M30];
|
||||
t[M31] = m[M30] * v[M01] + m[M31] * v[M11] + m[M32] * v[M21] + m[M33] * v[M31];
|
||||
t[M32] = m[M30] * v[M02] + m[M31] * v[M12] + m[M32] * v[M22] + m[M33] * v[M32];
|
||||
t[M33] = m[M30] * v[M03] + m[M31] * v[M13] + m[M32] * v[M23] + m[M33] * v[M33];
|
||||
return this.set(this.temp);
|
||||
}
|
||||
|
||||
Matrix4.tmpMatrix.identity();
|
||||
Matrix4.tmpMatrix.values[M03] = -position.x;
|
||||
Matrix4.tmpMatrix.values[M13] = -position.y;
|
||||
Matrix4.tmpMatrix.values[M23] = -position.z;
|
||||
this.multiply(Matrix4.tmpMatrix)
|
||||
lookAt(position: Vector3, direction: Vector3, up: Vector3) {
|
||||
Matrix4.initTemps();
|
||||
let xAxis = Matrix4.xAxis, yAxis = Matrix4.yAxis, zAxis = Matrix4.zAxis;
|
||||
zAxis.setFrom(direction).normalize();
|
||||
xAxis.setFrom(direction).normalize();
|
||||
xAxis.cross(up).normalize();
|
||||
yAxis.setFrom(xAxis).cross(zAxis).normalize();
|
||||
this.identity();
|
||||
let val = this.values;
|
||||
val[M00] = xAxis.x;
|
||||
val[M01] = xAxis.y;
|
||||
val[M02] = xAxis.z;
|
||||
val[M10] = yAxis.x;
|
||||
val[M11] = yAxis.y;
|
||||
val[M12] = yAxis.z;
|
||||
val[M20] = -zAxis.x;
|
||||
val[M21] = -zAxis.y;
|
||||
val[M22] = -zAxis.z;
|
||||
|
||||
return this;
|
||||
}
|
||||
Matrix4.tmpMatrix.identity();
|
||||
Matrix4.tmpMatrix.values[M03] = -position.x;
|
||||
Matrix4.tmpMatrix.values[M13] = -position.y;
|
||||
Matrix4.tmpMatrix.values[M23] = -position.z;
|
||||
this.multiply(Matrix4.tmpMatrix)
|
||||
|
||||
static initTemps () {
|
||||
if (Matrix4.xAxis === null) Matrix4.xAxis = new Vector3();
|
||||
if (Matrix4.yAxis === null) Matrix4.yAxis = new Vector3();
|
||||
if (Matrix4.zAxis === null) Matrix4.zAxis = new Vector3();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
static initTemps() {
|
||||
if (Matrix4.xAxis === null) Matrix4.xAxis = new Vector3();
|
||||
if (Matrix4.yAxis === null) Matrix4.yAxis = new Vector3();
|
||||
if (Matrix4.zAxis === null) Matrix4.zAxis = new Vector3();
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,182 +27,185 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
export class Mesh implements Disposable, Restorable {
|
||||
private context: ManagedWebGLRenderingContext;
|
||||
private vertices: Float32Array;
|
||||
private verticesBuffer: WebGLBuffer;
|
||||
private verticesLength = 0;
|
||||
private dirtyVertices = false;
|
||||
private indices: Uint16Array;
|
||||
private indicesBuffer: WebGLBuffer;
|
||||
private indicesLength = 0;
|
||||
private dirtyIndices = false;
|
||||
private elementsPerVertex = 0;
|
||||
import { Disposable, Restorable } from "spine-core";
|
||||
import { Shader } from "./Shader";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL";
|
||||
|
||||
getAttributes (): VertexAttribute[] { return this.attributes; }
|
||||
|
||||
maxVertices (): number { return this.vertices.length / this.elementsPerVertex; }
|
||||
numVertices (): number { return this.verticesLength / this.elementsPerVertex; }
|
||||
setVerticesLength (length: number) {
|
||||
this.dirtyVertices = true;
|
||||
this.verticesLength = length;
|
||||
export class Mesh implements Disposable, Restorable {
|
||||
private context: ManagedWebGLRenderingContext;
|
||||
private vertices: Float32Array;
|
||||
private verticesBuffer: WebGLBuffer;
|
||||
private verticesLength = 0;
|
||||
private dirtyVertices = false;
|
||||
private indices: Uint16Array;
|
||||
private indicesBuffer: WebGLBuffer;
|
||||
private indicesLength = 0;
|
||||
private dirtyIndices = false;
|
||||
private elementsPerVertex = 0;
|
||||
|
||||
getAttributes(): VertexAttribute[] { return this.attributes; }
|
||||
|
||||
maxVertices(): number { return this.vertices.length / this.elementsPerVertex; }
|
||||
numVertices(): number { return this.verticesLength / this.elementsPerVertex; }
|
||||
setVerticesLength(length: number) {
|
||||
this.dirtyVertices = true;
|
||||
this.verticesLength = length;
|
||||
}
|
||||
getVertices(): Float32Array { return this.vertices; }
|
||||
|
||||
maxIndices(): number { return this.indices.length; }
|
||||
numIndices(): number { return this.indicesLength; }
|
||||
setIndicesLength(length: number) {
|
||||
this.dirtyIndices = true;
|
||||
this.indicesLength = length;
|
||||
}
|
||||
getIndices(): Uint16Array { return this.indices };
|
||||
|
||||
getVertexSizeInFloats(): number {
|
||||
let size = 0;
|
||||
for (var i = 0; i < this.attributes.length; i++) {
|
||||
let attribute = this.attributes[i];
|
||||
size += attribute.numElements;
|
||||
}
|
||||
getVertices (): Float32Array { return this.vertices; }
|
||||
return size;
|
||||
}
|
||||
|
||||
maxIndices (): number { return this.indices.length; }
|
||||
numIndices (): number { return this.indicesLength; }
|
||||
setIndicesLength (length: number) {
|
||||
this.dirtyIndices = true;
|
||||
this.indicesLength = length;
|
||||
constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, private attributes: VertexAttribute[], maxVertices: number, maxIndices: number) {
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
this.elementsPerVertex = 0;
|
||||
for (let i = 0; i < attributes.length; i++) {
|
||||
this.elementsPerVertex += attributes[i].numElements;
|
||||
}
|
||||
getIndices (): Uint16Array { return this.indices };
|
||||
this.vertices = new Float32Array(maxVertices * this.elementsPerVertex);
|
||||
this.indices = new Uint16Array(maxIndices);
|
||||
this.context.addRestorable(this);
|
||||
}
|
||||
|
||||
getVertexSizeInFloats (): number {
|
||||
let size = 0;
|
||||
for (var i = 0; i < this.attributes.length; i++) {
|
||||
let attribute = this.attributes[i];
|
||||
size += attribute.numElements;
|
||||
setVertices(vertices: Array<number>) {
|
||||
this.dirtyVertices = true;
|
||||
if (vertices.length > this.vertices.length) throw Error("Mesh can't store more than " + this.maxVertices() + " vertices");
|
||||
this.vertices.set(vertices, 0);
|
||||
this.verticesLength = vertices.length;
|
||||
}
|
||||
|
||||
setIndices(indices: Array<number>) {
|
||||
this.dirtyIndices = true;
|
||||
if (indices.length > this.indices.length) throw Error("Mesh can't store more than " + this.maxIndices() + " indices");
|
||||
this.indices.set(indices, 0);
|
||||
this.indicesLength = indices.length;
|
||||
}
|
||||
|
||||
draw(shader: Shader, primitiveType: number) {
|
||||
this.drawWithOffset(shader, primitiveType, 0, this.indicesLength > 0 ? this.indicesLength : this.verticesLength / this.elementsPerVertex);
|
||||
}
|
||||
|
||||
drawWithOffset(shader: Shader, primitiveType: number, offset: number, count: number) {
|
||||
let gl = this.context.gl;
|
||||
if (this.dirtyVertices || this.dirtyIndices) this.update();
|
||||
this.bind(shader);
|
||||
if (this.indicesLength > 0) {
|
||||
gl.drawElements(primitiveType, count, gl.UNSIGNED_SHORT, offset * 2);
|
||||
} else {
|
||||
gl.drawArrays(primitiveType, offset, count);
|
||||
}
|
||||
this.unbind(shader);
|
||||
}
|
||||
|
||||
bind(shader: Shader) {
|
||||
let gl = this.context.gl;
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.verticesBuffer);
|
||||
let offset = 0;
|
||||
for (let i = 0; i < this.attributes.length; i++) {
|
||||
let attrib = this.attributes[i];
|
||||
let location = shader.getAttributeLocation(attrib.name);
|
||||
gl.enableVertexAttribArray(location);
|
||||
gl.vertexAttribPointer(location, attrib.numElements, gl.FLOAT, false, this.elementsPerVertex * 4, offset * 4);
|
||||
offset += attrib.numElements;
|
||||
}
|
||||
if (this.indicesLength > 0) gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer);
|
||||
}
|
||||
|
||||
unbind(shader: Shader) {
|
||||
let gl = this.context.gl;
|
||||
for (let i = 0; i < this.attributes.length; i++) {
|
||||
let attrib = this.attributes[i];
|
||||
let location = shader.getAttributeLocation(attrib.name);
|
||||
gl.disableVertexAttribArray(location);
|
||||
}
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||
if (this.indicesLength > 0) gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
|
||||
}
|
||||
|
||||
private update() {
|
||||
let gl = this.context.gl;
|
||||
if (this.dirtyVertices) {
|
||||
if (!this.verticesBuffer) {
|
||||
this.verticesBuffer = gl.createBuffer();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext, private attributes: VertexAttribute[], maxVertices: number, maxIndices: number) {
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
this.elementsPerVertex = 0;
|
||||
for (let i = 0; i < attributes.length; i++) {
|
||||
this.elementsPerVertex += attributes[i].numElements;
|
||||
}
|
||||
this.vertices = new Float32Array(maxVertices * this.elementsPerVertex);
|
||||
this.indices = new Uint16Array(maxIndices);
|
||||
this.context.addRestorable(this);
|
||||
}
|
||||
|
||||
setVertices (vertices: Array<number>) {
|
||||
this.dirtyVertices = true;
|
||||
if (vertices.length > this.vertices.length) throw Error("Mesh can't store more than " + this.maxVertices() + " vertices");
|
||||
this.vertices.set(vertices, 0);
|
||||
this.verticesLength = vertices.length;
|
||||
}
|
||||
|
||||
setIndices (indices: Array<number>) {
|
||||
this.dirtyIndices = true;
|
||||
if (indices.length > this.indices.length) throw Error("Mesh can't store more than " + this.maxIndices() + " indices");
|
||||
this.indices.set(indices, 0);
|
||||
this.indicesLength = indices.length;
|
||||
}
|
||||
|
||||
draw (shader: Shader, primitiveType: number) {
|
||||
this.drawWithOffset(shader, primitiveType, 0, this.indicesLength > 0 ? this.indicesLength : this.verticesLength / this.elementsPerVertex);
|
||||
}
|
||||
|
||||
drawWithOffset (shader: Shader, primitiveType: number, offset: number, count: number) {
|
||||
let gl = this.context.gl;
|
||||
if (this.dirtyVertices || this.dirtyIndices) this.update();
|
||||
this.bind(shader);
|
||||
if (this.indicesLength > 0) {
|
||||
gl.drawElements(primitiveType, count, gl.UNSIGNED_SHORT, offset * 2);
|
||||
} else {
|
||||
gl.drawArrays(primitiveType, offset, count);
|
||||
}
|
||||
this.unbind(shader);
|
||||
}
|
||||
|
||||
bind (shader: Shader) {
|
||||
let gl = this.context.gl;
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.verticesBuffer);
|
||||
let offset = 0;
|
||||
for (let i = 0; i < this.attributes.length; i++) {
|
||||
let attrib = this.attributes[i];
|
||||
let location = shader.getAttributeLocation(attrib.name);
|
||||
gl.enableVertexAttribArray(location);
|
||||
gl.vertexAttribPointer(location, attrib.numElements, gl.FLOAT, false, this.elementsPerVertex * 4, offset * 4);
|
||||
offset += attrib.numElements;
|
||||
gl.bufferData(gl.ARRAY_BUFFER, this.vertices.subarray(0, this.verticesLength), gl.DYNAMIC_DRAW);
|
||||
this.dirtyVertices = false;
|
||||
}
|
||||
|
||||
if (this.dirtyIndices) {
|
||||
if (!this.indicesBuffer) {
|
||||
this.indicesBuffer = gl.createBuffer();
|
||||
}
|
||||
if (this.indicesLength > 0) gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer);
|
||||
}
|
||||
|
||||
unbind (shader: Shader) {
|
||||
let gl = this.context.gl;
|
||||
for (let i = 0; i < this.attributes.length; i++) {
|
||||
let attrib = this.attributes[i];
|
||||
let location = shader.getAttributeLocation(attrib.name);
|
||||
gl.disableVertexAttribArray(location);
|
||||
}
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||
if (this.indicesLength > 0) gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
|
||||
}
|
||||
|
||||
private update () {
|
||||
let gl = this.context.gl;
|
||||
if (this.dirtyVertices) {
|
||||
if (!this.verticesBuffer) {
|
||||
this.verticesBuffer = gl.createBuffer();
|
||||
}
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.verticesBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, this.vertices.subarray(0, this.verticesLength), gl.DYNAMIC_DRAW);
|
||||
this.dirtyVertices = false;
|
||||
}
|
||||
|
||||
if (this.dirtyIndices) {
|
||||
if (!this.indicesBuffer) {
|
||||
this.indicesBuffer = gl.createBuffer();
|
||||
}
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer);
|
||||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices.subarray(0, this.indicesLength), gl.DYNAMIC_DRAW);
|
||||
this.dirtyIndices = false;
|
||||
}
|
||||
}
|
||||
|
||||
restore () {
|
||||
this.verticesBuffer = null;
|
||||
this.indicesBuffer = null;
|
||||
this.update();
|
||||
}
|
||||
|
||||
dispose () {
|
||||
this.context.removeRestorable(this);
|
||||
let gl = this.context.gl;
|
||||
gl.deleteBuffer(this.verticesBuffer);
|
||||
gl.deleteBuffer(this.indicesBuffer);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer);
|
||||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices.subarray(0, this.indicesLength), gl.DYNAMIC_DRAW);
|
||||
this.dirtyIndices = false;
|
||||
}
|
||||
}
|
||||
|
||||
export class VertexAttribute {
|
||||
constructor (public name: string, public type: VertexAttributeType, public numElements: number) { }
|
||||
restore() {
|
||||
this.verticesBuffer = null;
|
||||
this.indicesBuffer = null;
|
||||
this.update();
|
||||
}
|
||||
|
||||
export class Position2Attribute extends VertexAttribute {
|
||||
constructor () {
|
||||
super(Shader.POSITION, VertexAttributeType.Float, 2);
|
||||
}
|
||||
}
|
||||
|
||||
export class Position3Attribute extends VertexAttribute {
|
||||
constructor () {
|
||||
super(Shader.POSITION, VertexAttributeType.Float, 3);
|
||||
}
|
||||
}
|
||||
|
||||
export class TexCoordAttribute extends VertexAttribute {
|
||||
constructor (unit: number = 0) {
|
||||
super(Shader.TEXCOORDS + (unit == 0 ? "" : unit), VertexAttributeType.Float, 2);
|
||||
}
|
||||
}
|
||||
|
||||
export class ColorAttribute extends VertexAttribute {
|
||||
constructor () {
|
||||
super(Shader.COLOR, VertexAttributeType.Float, 4);
|
||||
}
|
||||
}
|
||||
|
||||
export class Color2Attribute extends VertexAttribute {
|
||||
constructor () {
|
||||
super(Shader.COLOR2, VertexAttributeType.Float, 4);
|
||||
}
|
||||
}
|
||||
|
||||
export enum VertexAttributeType {
|
||||
Float
|
||||
dispose() {
|
||||
this.context.removeRestorable(this);
|
||||
let gl = this.context.gl;
|
||||
gl.deleteBuffer(this.verticesBuffer);
|
||||
gl.deleteBuffer(this.indicesBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
export class VertexAttribute {
|
||||
constructor(public name: string, public type: VertexAttributeType, public numElements: number) { }
|
||||
}
|
||||
|
||||
export class Position2Attribute extends VertexAttribute {
|
||||
constructor() {
|
||||
super(Shader.POSITION, VertexAttributeType.Float, 2);
|
||||
}
|
||||
}
|
||||
|
||||
export class Position3Attribute extends VertexAttribute {
|
||||
constructor() {
|
||||
super(Shader.POSITION, VertexAttributeType.Float, 3);
|
||||
}
|
||||
}
|
||||
|
||||
export class TexCoordAttribute extends VertexAttribute {
|
||||
constructor(unit: number = 0) {
|
||||
super(Shader.TEXCOORDS + (unit == 0 ? "" : unit), VertexAttributeType.Float, 2);
|
||||
}
|
||||
}
|
||||
|
||||
export class ColorAttribute extends VertexAttribute {
|
||||
constructor() {
|
||||
super(Shader.COLOR, VertexAttributeType.Float, 4);
|
||||
}
|
||||
}
|
||||
|
||||
export class Color2Attribute extends VertexAttribute {
|
||||
constructor() {
|
||||
super(Shader.COLOR2, VertexAttributeType.Float, 4);
|
||||
}
|
||||
}
|
||||
|
||||
export enum VertexAttributeType {
|
||||
Float
|
||||
}
|
||||
|
||||
@ -27,107 +27,111 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
export class PolygonBatcher implements Disposable {
|
||||
private context: ManagedWebGLRenderingContext;
|
||||
private drawCalls: number;
|
||||
private isDrawing = false;
|
||||
private mesh: Mesh;
|
||||
private shader: Shader = null;
|
||||
private lastTexture: GLTexture = null;
|
||||
private verticesLength = 0;
|
||||
private indicesLength = 0;
|
||||
private srcColorBlend: number;
|
||||
private srcAlphaBlend: number;
|
||||
private dstBlend: number;
|
||||
import { Disposable } from "spine-core";
|
||||
import { GLTexture } from "./GLTexture";
|
||||
import { Mesh, Position2Attribute, ColorAttribute, TexCoordAttribute, Color2Attribute } from "./Mesh";
|
||||
import { Shader } from "./Shader";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL";
|
||||
|
||||
constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext, twoColorTint: boolean = true, maxVertices: number = 10920) {
|
||||
if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
let attributes = twoColorTint ?
|
||||
[new Position2Attribute(), new ColorAttribute(), new TexCoordAttribute(), new Color2Attribute()] :
|
||||
[new Position2Attribute(), new ColorAttribute(), new TexCoordAttribute()];
|
||||
this.mesh = new Mesh(context, attributes, maxVertices, maxVertices * 3);
|
||||
export class PolygonBatcher implements Disposable {
|
||||
private context: ManagedWebGLRenderingContext;
|
||||
private drawCalls: number;
|
||||
private isDrawing = false;
|
||||
private mesh: Mesh;
|
||||
private shader: Shader = null;
|
||||
private lastTexture: GLTexture = null;
|
||||
private verticesLength = 0;
|
||||
private indicesLength = 0;
|
||||
private srcColorBlend: number;
|
||||
private srcAlphaBlend: number;
|
||||
private dstBlend: number;
|
||||
|
||||
constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, twoColorTint: boolean = true, maxVertices: number = 10920) {
|
||||
if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
let attributes = twoColorTint ?
|
||||
[new Position2Attribute(), new ColorAttribute(), new TexCoordAttribute(), new Color2Attribute()] :
|
||||
[new Position2Attribute(), new ColorAttribute(), new TexCoordAttribute()];
|
||||
this.mesh = new Mesh(context, attributes, maxVertices, maxVertices * 3);
|
||||
let gl = this.context.gl;
|
||||
this.srcColorBlend = gl.SRC_ALPHA;
|
||||
this.srcAlphaBlend = gl.ONE;
|
||||
this.dstBlend = gl.ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
|
||||
begin(shader: Shader) {
|
||||
if (this.isDrawing) throw new Error("PolygonBatch is already drawing. Call PolygonBatch.end() before calling PolygonBatch.begin()");
|
||||
this.drawCalls = 0;
|
||||
this.shader = shader;
|
||||
this.lastTexture = null;
|
||||
this.isDrawing = true;
|
||||
|
||||
let gl = this.context.gl;
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendFuncSeparate(this.srcColorBlend, this.dstBlend, this.srcAlphaBlend, this.dstBlend);
|
||||
}
|
||||
|
||||
setBlendMode(srcColorBlend: number, srcAlphaBlend: number, dstBlend: number) {
|
||||
this.srcColorBlend = srcColorBlend;
|
||||
this.srcAlphaBlend = srcAlphaBlend;
|
||||
this.dstBlend = dstBlend;
|
||||
if (this.isDrawing) {
|
||||
this.flush();
|
||||
let gl = this.context.gl;
|
||||
this.srcColorBlend = gl.SRC_ALPHA;
|
||||
this.srcAlphaBlend = gl.ONE;
|
||||
this.dstBlend = gl.ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
|
||||
begin (shader: Shader) {
|
||||
if (this.isDrawing) throw new Error("PolygonBatch is already drawing. Call PolygonBatch.end() before calling PolygonBatch.begin()");
|
||||
this.drawCalls = 0;
|
||||
this.shader = shader;
|
||||
this.lastTexture = null;
|
||||
this.isDrawing = true;
|
||||
|
||||
let gl = this.context.gl;
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendFuncSeparate(this.srcColorBlend, this.dstBlend, this.srcAlphaBlend, this.dstBlend);
|
||||
}
|
||||
|
||||
setBlendMode (srcColorBlend: number, srcAlphaBlend: number, dstBlend: number) {
|
||||
this.srcColorBlend = srcColorBlend;
|
||||
this.srcAlphaBlend = srcAlphaBlend;
|
||||
this.dstBlend = dstBlend;
|
||||
if (this.isDrawing) {
|
||||
this.flush();
|
||||
let gl = this.context.gl;
|
||||
gl.blendFuncSeparate(srcColorBlend, dstBlend, srcAlphaBlend, dstBlend);
|
||||
}
|
||||
}
|
||||
|
||||
draw (texture: GLTexture, vertices: ArrayLike<number>, indices: Array<number>) {
|
||||
if (texture != this.lastTexture) {
|
||||
this.flush();
|
||||
this.lastTexture = texture;
|
||||
} else if (this.verticesLength + vertices.length > this.mesh.getVertices().length ||
|
||||
this.indicesLength + indices.length > this.mesh.getIndices().length) {
|
||||
this.flush();
|
||||
}
|
||||
|
||||
let indexStart = this.mesh.numVertices();
|
||||
this.mesh.getVertices().set(vertices, this.verticesLength);
|
||||
this.verticesLength += vertices.length;
|
||||
this.mesh.setVerticesLength(this.verticesLength)
|
||||
|
||||
let indicesArray = this.mesh.getIndices();
|
||||
for (let i = this.indicesLength, j = 0; j < indices.length; i++, j++)
|
||||
indicesArray[i] = indices[j] + indexStart;
|
||||
this.indicesLength += indices.length;
|
||||
this.mesh.setIndicesLength(this.indicesLength);
|
||||
}
|
||||
|
||||
flush () {
|
||||
if (this.verticesLength == 0) return;
|
||||
|
||||
this.lastTexture.bind();
|
||||
this.mesh.draw(this.shader, this.context.gl.TRIANGLES);
|
||||
|
||||
this.verticesLength = 0;
|
||||
this.indicesLength = 0;
|
||||
this.mesh.setVerticesLength(0);
|
||||
this.mesh.setIndicesLength(0);
|
||||
this.drawCalls++;
|
||||
}
|
||||
|
||||
end () {
|
||||
if (!this.isDrawing) throw new Error("PolygonBatch is not drawing. Call PolygonBatch.begin() before calling PolygonBatch.end()");
|
||||
if (this.verticesLength > 0 || this.indicesLength > 0) this.flush();
|
||||
this.shader = null;
|
||||
this.lastTexture = null;
|
||||
this.isDrawing = false;
|
||||
|
||||
let gl = this.context.gl;
|
||||
gl.disable(gl.BLEND);
|
||||
}
|
||||
|
||||
getDrawCalls () {
|
||||
return this.drawCalls;
|
||||
}
|
||||
|
||||
dispose () {
|
||||
this.mesh.dispose();
|
||||
gl.blendFuncSeparate(srcColorBlend, dstBlend, srcAlphaBlend, dstBlend);
|
||||
}
|
||||
}
|
||||
|
||||
draw(texture: GLTexture, vertices: ArrayLike<number>, indices: Array<number>) {
|
||||
if (texture != this.lastTexture) {
|
||||
this.flush();
|
||||
this.lastTexture = texture;
|
||||
} else if (this.verticesLength + vertices.length > this.mesh.getVertices().length ||
|
||||
this.indicesLength + indices.length > this.mesh.getIndices().length) {
|
||||
this.flush();
|
||||
}
|
||||
|
||||
let indexStart = this.mesh.numVertices();
|
||||
this.mesh.getVertices().set(vertices, this.verticesLength);
|
||||
this.verticesLength += vertices.length;
|
||||
this.mesh.setVerticesLength(this.verticesLength)
|
||||
|
||||
let indicesArray = this.mesh.getIndices();
|
||||
for (let i = this.indicesLength, j = 0; j < indices.length; i++, j++)
|
||||
indicesArray[i] = indices[j] + indexStart;
|
||||
this.indicesLength += indices.length;
|
||||
this.mesh.setIndicesLength(this.indicesLength);
|
||||
}
|
||||
|
||||
flush() {
|
||||
if (this.verticesLength == 0) return;
|
||||
|
||||
this.lastTexture.bind();
|
||||
this.mesh.draw(this.shader, this.context.gl.TRIANGLES);
|
||||
|
||||
this.verticesLength = 0;
|
||||
this.indicesLength = 0;
|
||||
this.mesh.setVerticesLength(0);
|
||||
this.mesh.setIndicesLength(0);
|
||||
this.drawCalls++;
|
||||
}
|
||||
|
||||
end() {
|
||||
if (!this.isDrawing) throw new Error("PolygonBatch is not drawing. Call PolygonBatch.begin() before calling PolygonBatch.end()");
|
||||
if (this.verticesLength > 0 || this.indicesLength > 0) this.flush();
|
||||
this.shader = null;
|
||||
this.lastTexture = null;
|
||||
this.isDrawing = false;
|
||||
|
||||
let gl = this.context.gl;
|
||||
gl.disable(gl.BLEND);
|
||||
}
|
||||
|
||||
getDrawCalls() {
|
||||
return this.drawCalls;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.mesh.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,480 +27,489 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
const quad = [
|
||||
0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 0, 0,
|
||||
];
|
||||
const QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
||||
const WHITE = new Color(1, 1, 1, 1);
|
||||
import { Color, Disposable, Skeleton, MathUtils, TextureAtlasRegion } from "spine-core";
|
||||
import { OrthoCamera } from "./Camera";
|
||||
import { GLTexture } from "./GLTexture";
|
||||
import { PolygonBatcher } from "./PolygonBatcher";
|
||||
import { Shader } from "./Shader";
|
||||
import { ShapeRenderer } from "./ShapeRenderer";
|
||||
import { SkeletonDebugRenderer } from "./SkeletonDebugRenderer";
|
||||
import { SkeletonRenderer } from "./SkeletonRenderer";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL";
|
||||
;
|
||||
|
||||
export class SceneRenderer implements Disposable {
|
||||
context: ManagedWebGLRenderingContext;
|
||||
canvas: HTMLCanvasElement;
|
||||
camera: OrthoCamera;
|
||||
batcher: PolygonBatcher;
|
||||
private twoColorTint = false;
|
||||
private batcherShader: Shader;
|
||||
private shapes: ShapeRenderer;
|
||||
private shapesShader: Shader;
|
||||
private activeRenderer: PolygonBatcher | ShapeRenderer | SkeletonDebugRenderer;
|
||||
skeletonRenderer: SkeletonRenderer;
|
||||
skeletonDebugRenderer: SkeletonDebugRenderer;
|
||||
const quad = [
|
||||
0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 0, 0,
|
||||
];
|
||||
const QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
||||
const WHITE = new Color(1, 1, 1, 1);
|
||||
|
||||
constructor (canvas: HTMLCanvasElement, context: ManagedWebGLRenderingContext | WebGLRenderingContext, twoColorTint: boolean = true) {
|
||||
this.canvas = canvas;
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
this.twoColorTint = twoColorTint;
|
||||
this.camera = new OrthoCamera(canvas.width, canvas.height);
|
||||
this.batcherShader = twoColorTint ? Shader.newTwoColoredTextured(this.context) : Shader.newColoredTextured(this.context);
|
||||
this.batcher = new PolygonBatcher(this.context, twoColorTint);
|
||||
this.shapesShader = Shader.newColored(this.context);
|
||||
this.shapes = new ShapeRenderer(this.context);
|
||||
this.skeletonRenderer = new SkeletonRenderer(this.context, twoColorTint);
|
||||
this.skeletonDebugRenderer = new SkeletonDebugRenderer(this.context);
|
||||
}
|
||||
export class SceneRenderer implements Disposable {
|
||||
context: ManagedWebGLRenderingContext;
|
||||
canvas: HTMLCanvasElement;
|
||||
camera: OrthoCamera;
|
||||
batcher: PolygonBatcher;
|
||||
private twoColorTint = false;
|
||||
private batcherShader: Shader;
|
||||
private shapes: ShapeRenderer;
|
||||
private shapesShader: Shader;
|
||||
private activeRenderer: PolygonBatcher | ShapeRenderer | SkeletonDebugRenderer;
|
||||
skeletonRenderer: SkeletonRenderer;
|
||||
skeletonDebugRenderer: SkeletonDebugRenderer;
|
||||
|
||||
begin () {
|
||||
this.camera.update();
|
||||
this.enableRenderer(this.batcher);
|
||||
}
|
||||
|
||||
drawSkeleton (skeleton: Skeleton, premultipliedAlpha = false, slotRangeStart = -1, slotRangeEnd = -1) {
|
||||
this.enableRenderer(this.batcher);
|
||||
this.skeletonRenderer.premultipliedAlpha = premultipliedAlpha;
|
||||
this.skeletonRenderer.draw(this.batcher, skeleton, slotRangeStart, slotRangeEnd);
|
||||
}
|
||||
|
||||
drawSkeletonDebug (skeleton: Skeleton, premultipliedAlpha = false, ignoredBones: Array<string> = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.skeletonDebugRenderer.premultipliedAlpha = premultipliedAlpha;
|
||||
this.skeletonDebugRenderer.draw(this.shapes, skeleton, ignoredBones);
|
||||
}
|
||||
|
||||
drawTexture (texture: GLTexture, x: number, y: number, width: number, height: number, color: Color = null) {
|
||||
this.enableRenderer(this.batcher);
|
||||
if (color === null) color = WHITE;
|
||||
var i = 0;
|
||||
quad[i++] = x;
|
||||
quad[i++] = y;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 1;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x + width;
|
||||
quad[i++] = y;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 1;
|
||||
quad[i++] = 1;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x + width;
|
||||
quad[i++] = y + height;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 1;
|
||||
quad[i++] = 0;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x;
|
||||
quad[i++] = y + height;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i] = 0;
|
||||
}
|
||||
this.batcher.draw(texture, quad, QUAD_TRIANGLES);
|
||||
}
|
||||
|
||||
drawTextureUV (texture: GLTexture, x: number, y: number, width: number, height: number, u: number, v: number, u2: number, v2: number, color: Color = null) {
|
||||
this.enableRenderer(this.batcher);
|
||||
if (color === null) color = WHITE;
|
||||
var i = 0;
|
||||
quad[i++] = x;
|
||||
quad[i++] = y;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = u;
|
||||
quad[i++] = v;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x + width;
|
||||
quad[i++] = y;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = u2;
|
||||
quad[i++] = v;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x + width;
|
||||
quad[i++] = y + height;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = u2;
|
||||
quad[i++] = v2;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x;
|
||||
quad[i++] = y + height;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = u;
|
||||
quad[i++] = v2;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i] = 0;
|
||||
}
|
||||
this.batcher.draw(texture, quad, QUAD_TRIANGLES);
|
||||
}
|
||||
|
||||
drawTextureRotated (texture: GLTexture, x: number, y: number, width: number, height: number, pivotX: number, pivotY: number, angle: number, color: Color = null) {
|
||||
this.enableRenderer(this.batcher);
|
||||
if (color === null) color = WHITE;
|
||||
|
||||
// bottom left and top right corner points relative to origin
|
||||
let worldOriginX = x + pivotX;
|
||||
let worldOriginY = y + pivotY;
|
||||
let fx = -pivotX;
|
||||
let fy = -pivotY;
|
||||
let fx2 = width - pivotX;
|
||||
let fy2 = height - pivotY;
|
||||
|
||||
// construct corner points, start from top left and go counter clockwise
|
||||
let p1x = fx;
|
||||
let p1y = fy;
|
||||
let p2x = fx;
|
||||
let p2y = fy2;
|
||||
let p3x = fx2;
|
||||
let p3y = fy2;
|
||||
let p4x = fx2;
|
||||
let p4y = fy;
|
||||
|
||||
let x1 = 0;
|
||||
let y1 = 0;
|
||||
let x2 = 0;
|
||||
let y2 = 0;
|
||||
let x3 = 0;
|
||||
let y3 = 0;
|
||||
let x4 = 0;
|
||||
let y4 = 0;
|
||||
|
||||
// rotate
|
||||
if (angle != 0) {
|
||||
let cos = MathUtils.cosDeg(angle);
|
||||
let sin = MathUtils.sinDeg(angle);
|
||||
|
||||
x1 = cos * p1x - sin * p1y;
|
||||
y1 = sin * p1x + cos * p1y;
|
||||
|
||||
x4 = cos * p2x - sin * p2y;
|
||||
y4 = sin * p2x + cos * p2y;
|
||||
|
||||
x3 = cos * p3x - sin * p3y;
|
||||
y3 = sin * p3x + cos * p3y;
|
||||
|
||||
x2 = x3 + (x1 - x4);
|
||||
y2 = y3 + (y1 - y4);
|
||||
} else {
|
||||
x1 = p1x;
|
||||
y1 = p1y;
|
||||
|
||||
x4 = p2x;
|
||||
y4 = p2y;
|
||||
|
||||
x3 = p3x;
|
||||
y3 = p3y;
|
||||
|
||||
x2 = p4x;
|
||||
y2 = p4y;
|
||||
}
|
||||
|
||||
x1 += worldOriginX;
|
||||
y1 += worldOriginY;
|
||||
x2 += worldOriginX;
|
||||
y2 += worldOriginY;
|
||||
x3 += worldOriginX;
|
||||
y3 += worldOriginY;
|
||||
x4 += worldOriginX;
|
||||
y4 += worldOriginY;
|
||||
|
||||
var i = 0;
|
||||
quad[i++] = x1;
|
||||
quad[i++] = y1;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 1;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x2;
|
||||
quad[i++] = y2;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 1;
|
||||
quad[i++] = 1;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x3;
|
||||
quad[i++] = y3;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 1;
|
||||
quad[i++] = 0;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x4;
|
||||
quad[i++] = y4;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i] = 0;
|
||||
}
|
||||
this.batcher.draw(texture, quad, QUAD_TRIANGLES);
|
||||
}
|
||||
|
||||
drawRegion (region: TextureAtlasRegion, x: number, y: number, width: number, height: number, color: Color = null) {
|
||||
this.enableRenderer(this.batcher);
|
||||
if (color === null) color = WHITE;
|
||||
var i = 0;
|
||||
quad[i++] = x;
|
||||
quad[i++] = y;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = region.u;
|
||||
quad[i++] = region.v2;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x + width;
|
||||
quad[i++] = y;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = region.u2;
|
||||
quad[i++] = region.v2;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x + width;
|
||||
quad[i++] = y + height;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = region.u2;
|
||||
quad[i++] = region.v;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x;
|
||||
quad[i++] = y + height;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = region.u;
|
||||
quad[i++] = region.v;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i] = 0;
|
||||
}
|
||||
this.batcher.draw(<GLTexture>region.page.texture, quad, QUAD_TRIANGLES);
|
||||
}
|
||||
|
||||
line (x: number, y: number, x2: number, y2: number, color: Color = null, color2: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.line(x, y, x2, y2, color);
|
||||
}
|
||||
|
||||
triangle (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, color: Color = null, color2: Color = null, color3: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.triangle(filled, x, y, x2, y2, x3, y3, color, color2, color3);
|
||||
}
|
||||
|
||||
quad (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, color: Color = null, color2: Color = null, color3: Color = null, color4: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.quad(filled, x, y, x2, y2, x3, y3, x4, y4, color, color2, color3, color4);
|
||||
}
|
||||
|
||||
rect (filled: boolean, x: number, y: number, width: number, height: number, color: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.rect(filled, x, y, width, height, color);
|
||||
}
|
||||
|
||||
rectLine (filled: boolean, x1: number, y1: number, x2: number, y2: number, width: number, color: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.rectLine(filled, x1, y1, x2, y2, width, color);
|
||||
}
|
||||
|
||||
polygon (polygonVertices: ArrayLike<number>, offset: number, count: number, color: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.polygon(polygonVertices, offset, count, color);
|
||||
}
|
||||
|
||||
circle (filled: boolean, x: number, y: number, radius: number, color: Color = null, segments: number = 0) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.circle(filled, x, y, radius, color, segments);
|
||||
}
|
||||
|
||||
curve (x1: number, y1: number, cx1: number, cy1: number, cx2: number, cy2: number, x2: number, y2: number, segments: number, color: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, segments, color);
|
||||
}
|
||||
|
||||
end () {
|
||||
if (this.activeRenderer === this.batcher) this.batcher.end();
|
||||
else if (this.activeRenderer === this.shapes) this.shapes.end();
|
||||
this.activeRenderer = null;
|
||||
}
|
||||
|
||||
resize (resizeMode: ResizeMode) {
|
||||
let canvas = this.canvas;
|
||||
var dpr = window.devicePixelRatio || 1;
|
||||
var w = Math.round(canvas.clientWidth * dpr);
|
||||
var h = Math.round(canvas.clientHeight * dpr);
|
||||
|
||||
if (canvas.width != w || canvas.height != h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
}
|
||||
this.context.gl.viewport(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Nothing to do for stretch, we simply apply the viewport size of the camera.
|
||||
if (resizeMode === ResizeMode.Expand)
|
||||
this.camera.setViewport(w, h);
|
||||
else if (resizeMode === ResizeMode.Fit) {
|
||||
let sourceWidth = canvas.width, sourceHeight = canvas.height;
|
||||
let targetWidth = this.camera.viewportWidth, targetHeight = this.camera.viewportHeight;
|
||||
let targetRatio = targetHeight / targetWidth;
|
||||
let sourceRatio = sourceHeight / sourceWidth;
|
||||
let scale = targetRatio < sourceRatio ? targetWidth / sourceWidth : targetHeight / sourceHeight;
|
||||
this.camera.setViewport(sourceWidth * scale, sourceHeight * scale);
|
||||
}
|
||||
this.camera.update();
|
||||
}
|
||||
|
||||
private enableRenderer (renderer: PolygonBatcher | ShapeRenderer | SkeletonDebugRenderer) {
|
||||
if (this.activeRenderer === renderer) return;
|
||||
this.end();
|
||||
if (renderer instanceof PolygonBatcher) {
|
||||
this.batcherShader.bind();
|
||||
this.batcherShader.setUniform4x4f(Shader.MVP_MATRIX, this.camera.projectionView.values);
|
||||
this.batcherShader.setUniformi("u_texture", 0);
|
||||
this.batcher.begin(this.batcherShader);
|
||||
this.activeRenderer = this.batcher;
|
||||
} else if (renderer instanceof ShapeRenderer) {
|
||||
this.shapesShader.bind();
|
||||
this.shapesShader.setUniform4x4f(Shader.MVP_MATRIX, this.camera.projectionView.values);
|
||||
this.shapes.begin(this.shapesShader);
|
||||
this.activeRenderer = this.shapes;
|
||||
} else
|
||||
this.activeRenderer = this.skeletonDebugRenderer;
|
||||
}
|
||||
|
||||
dispose () {
|
||||
this.batcher.dispose();
|
||||
this.batcherShader.dispose();
|
||||
this.shapes.dispose();
|
||||
this.shapesShader.dispose();
|
||||
this.skeletonDebugRenderer.dispose();
|
||||
}
|
||||
constructor(canvas: HTMLCanvasElement, context: ManagedWebGLRenderingContext | WebGLRenderingContext, twoColorTint: boolean = true) {
|
||||
this.canvas = canvas;
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
this.twoColorTint = twoColorTint;
|
||||
this.camera = new OrthoCamera(canvas.width, canvas.height);
|
||||
this.batcherShader = twoColorTint ? Shader.newTwoColoredTextured(this.context) : Shader.newColoredTextured(this.context);
|
||||
this.batcher = new PolygonBatcher(this.context, twoColorTint);
|
||||
this.shapesShader = Shader.newColored(this.context);
|
||||
this.shapes = new ShapeRenderer(this.context);
|
||||
this.skeletonRenderer = new SkeletonRenderer(this.context, twoColorTint);
|
||||
this.skeletonDebugRenderer = new SkeletonDebugRenderer(this.context);
|
||||
}
|
||||
|
||||
export enum ResizeMode {
|
||||
Stretch,
|
||||
Expand,
|
||||
Fit
|
||||
begin() {
|
||||
this.camera.update();
|
||||
this.enableRenderer(this.batcher);
|
||||
}
|
||||
|
||||
drawSkeleton(skeleton: Skeleton, premultipliedAlpha = false, slotRangeStart = -1, slotRangeEnd = -1) {
|
||||
this.enableRenderer(this.batcher);
|
||||
this.skeletonRenderer.premultipliedAlpha = premultipliedAlpha;
|
||||
this.skeletonRenderer.draw(this.batcher, skeleton, slotRangeStart, slotRangeEnd);
|
||||
}
|
||||
|
||||
drawSkeletonDebug(skeleton: Skeleton, premultipliedAlpha = false, ignoredBones: Array<string> = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.skeletonDebugRenderer.premultipliedAlpha = premultipliedAlpha;
|
||||
this.skeletonDebugRenderer.draw(this.shapes, skeleton, ignoredBones);
|
||||
}
|
||||
|
||||
drawTexture(texture: GLTexture, x: number, y: number, width: number, height: number, color: Color = null) {
|
||||
this.enableRenderer(this.batcher);
|
||||
if (color === null) color = WHITE;
|
||||
var i = 0;
|
||||
quad[i++] = x;
|
||||
quad[i++] = y;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 1;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x + width;
|
||||
quad[i++] = y;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 1;
|
||||
quad[i++] = 1;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x + width;
|
||||
quad[i++] = y + height;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 1;
|
||||
quad[i++] = 0;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x;
|
||||
quad[i++] = y + height;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i] = 0;
|
||||
}
|
||||
this.batcher.draw(texture, quad, QUAD_TRIANGLES);
|
||||
}
|
||||
|
||||
drawTextureUV(texture: GLTexture, x: number, y: number, width: number, height: number, u: number, v: number, u2: number, v2: number, color: Color = null) {
|
||||
this.enableRenderer(this.batcher);
|
||||
if (color === null) color = WHITE;
|
||||
var i = 0;
|
||||
quad[i++] = x;
|
||||
quad[i++] = y;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = u;
|
||||
quad[i++] = v;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x + width;
|
||||
quad[i++] = y;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = u2;
|
||||
quad[i++] = v;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x + width;
|
||||
quad[i++] = y + height;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = u2;
|
||||
quad[i++] = v2;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x;
|
||||
quad[i++] = y + height;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = u;
|
||||
quad[i++] = v2;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i] = 0;
|
||||
}
|
||||
this.batcher.draw(texture, quad, QUAD_TRIANGLES);
|
||||
}
|
||||
|
||||
drawTextureRotated(texture: GLTexture, x: number, y: number, width: number, height: number, pivotX: number, pivotY: number, angle: number, color: Color = null) {
|
||||
this.enableRenderer(this.batcher);
|
||||
if (color === null) color = WHITE;
|
||||
|
||||
// bottom left and top right corner points relative to origin
|
||||
let worldOriginX = x + pivotX;
|
||||
let worldOriginY = y + pivotY;
|
||||
let fx = -pivotX;
|
||||
let fy = -pivotY;
|
||||
let fx2 = width - pivotX;
|
||||
let fy2 = height - pivotY;
|
||||
|
||||
// construct corner points, start from top left and go counter clockwise
|
||||
let p1x = fx;
|
||||
let p1y = fy;
|
||||
let p2x = fx;
|
||||
let p2y = fy2;
|
||||
let p3x = fx2;
|
||||
let p3y = fy2;
|
||||
let p4x = fx2;
|
||||
let p4y = fy;
|
||||
|
||||
let x1 = 0;
|
||||
let y1 = 0;
|
||||
let x2 = 0;
|
||||
let y2 = 0;
|
||||
let x3 = 0;
|
||||
let y3 = 0;
|
||||
let x4 = 0;
|
||||
let y4 = 0;
|
||||
|
||||
// rotate
|
||||
if (angle != 0) {
|
||||
let cos = MathUtils.cosDeg(angle);
|
||||
let sin = MathUtils.sinDeg(angle);
|
||||
|
||||
x1 = cos * p1x - sin * p1y;
|
||||
y1 = sin * p1x + cos * p1y;
|
||||
|
||||
x4 = cos * p2x - sin * p2y;
|
||||
y4 = sin * p2x + cos * p2y;
|
||||
|
||||
x3 = cos * p3x - sin * p3y;
|
||||
y3 = sin * p3x + cos * p3y;
|
||||
|
||||
x2 = x3 + (x1 - x4);
|
||||
y2 = y3 + (y1 - y4);
|
||||
} else {
|
||||
x1 = p1x;
|
||||
y1 = p1y;
|
||||
|
||||
x4 = p2x;
|
||||
y4 = p2y;
|
||||
|
||||
x3 = p3x;
|
||||
y3 = p3y;
|
||||
|
||||
x2 = p4x;
|
||||
y2 = p4y;
|
||||
}
|
||||
|
||||
x1 += worldOriginX;
|
||||
y1 += worldOriginY;
|
||||
x2 += worldOriginX;
|
||||
y2 += worldOriginY;
|
||||
x3 += worldOriginX;
|
||||
y3 += worldOriginY;
|
||||
x4 += worldOriginX;
|
||||
y4 += worldOriginY;
|
||||
|
||||
var i = 0;
|
||||
quad[i++] = x1;
|
||||
quad[i++] = y1;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 1;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x2;
|
||||
quad[i++] = y2;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 1;
|
||||
quad[i++] = 1;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x3;
|
||||
quad[i++] = y3;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 1;
|
||||
quad[i++] = 0;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x4;
|
||||
quad[i++] = y4;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i] = 0;
|
||||
}
|
||||
this.batcher.draw(texture, quad, QUAD_TRIANGLES);
|
||||
}
|
||||
|
||||
drawRegion(region: TextureAtlasRegion, x: number, y: number, width: number, height: number, color: Color = null) {
|
||||
this.enableRenderer(this.batcher);
|
||||
if (color === null) color = WHITE;
|
||||
var i = 0;
|
||||
quad[i++] = x;
|
||||
quad[i++] = y;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = region.u;
|
||||
quad[i++] = region.v2;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x + width;
|
||||
quad[i++] = y;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = region.u2;
|
||||
quad[i++] = region.v2;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x + width;
|
||||
quad[i++] = y + height;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = region.u2;
|
||||
quad[i++] = region.v;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
}
|
||||
quad[i++] = x;
|
||||
quad[i++] = y + height;
|
||||
quad[i++] = color.r;
|
||||
quad[i++] = color.g;
|
||||
quad[i++] = color.b;
|
||||
quad[i++] = color.a;
|
||||
quad[i++] = region.u;
|
||||
quad[i++] = region.v;
|
||||
if (this.twoColorTint) {
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i++] = 0;
|
||||
quad[i] = 0;
|
||||
}
|
||||
this.batcher.draw(<GLTexture>region.page.texture, quad, QUAD_TRIANGLES);
|
||||
}
|
||||
|
||||
line(x: number, y: number, x2: number, y2: number, color: Color = null, color2: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.line(x, y, x2, y2, color);
|
||||
}
|
||||
|
||||
triangle(filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, color: Color = null, color2: Color = null, color3: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.triangle(filled, x, y, x2, y2, x3, y3, color, color2, color3);
|
||||
}
|
||||
|
||||
quad(filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, color: Color = null, color2: Color = null, color3: Color = null, color4: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.quad(filled, x, y, x2, y2, x3, y3, x4, y4, color, color2, color3, color4);
|
||||
}
|
||||
|
||||
rect(filled: boolean, x: number, y: number, width: number, height: number, color: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.rect(filled, x, y, width, height, color);
|
||||
}
|
||||
|
||||
rectLine(filled: boolean, x1: number, y1: number, x2: number, y2: number, width: number, color: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.rectLine(filled, x1, y1, x2, y2, width, color);
|
||||
}
|
||||
|
||||
polygon(polygonVertices: ArrayLike<number>, offset: number, count: number, color: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.polygon(polygonVertices, offset, count, color);
|
||||
}
|
||||
|
||||
circle(filled: boolean, x: number, y: number, radius: number, color: Color = null, segments: number = 0) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.circle(filled, x, y, radius, color, segments);
|
||||
}
|
||||
|
||||
curve(x1: number, y1: number, cx1: number, cy1: number, cx2: number, cy2: number, x2: number, y2: number, segments: number, color: Color = null) {
|
||||
this.enableRenderer(this.shapes);
|
||||
this.shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, segments, color);
|
||||
}
|
||||
|
||||
end() {
|
||||
if (this.activeRenderer === this.batcher) this.batcher.end();
|
||||
else if (this.activeRenderer === this.shapes) this.shapes.end();
|
||||
this.activeRenderer = null;
|
||||
}
|
||||
|
||||
resize(resizeMode: ResizeMode) {
|
||||
let canvas = this.canvas;
|
||||
var dpr = window.devicePixelRatio || 1;
|
||||
var w = Math.round(canvas.clientWidth * dpr);
|
||||
var h = Math.round(canvas.clientHeight * dpr);
|
||||
|
||||
if (canvas.width != w || canvas.height != h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
}
|
||||
this.context.gl.viewport(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Nothing to do for stretch, we simply apply the viewport size of the camera.
|
||||
if (resizeMode === ResizeMode.Expand)
|
||||
this.camera.setViewport(w, h);
|
||||
else if (resizeMode === ResizeMode.Fit) {
|
||||
let sourceWidth = canvas.width, sourceHeight = canvas.height;
|
||||
let targetWidth = this.camera.viewportWidth, targetHeight = this.camera.viewportHeight;
|
||||
let targetRatio = targetHeight / targetWidth;
|
||||
let sourceRatio = sourceHeight / sourceWidth;
|
||||
let scale = targetRatio < sourceRatio ? targetWidth / sourceWidth : targetHeight / sourceHeight;
|
||||
this.camera.setViewport(sourceWidth * scale, sourceHeight * scale);
|
||||
}
|
||||
this.camera.update();
|
||||
}
|
||||
|
||||
private enableRenderer(renderer: PolygonBatcher | ShapeRenderer | SkeletonDebugRenderer) {
|
||||
if (this.activeRenderer === renderer) return;
|
||||
this.end();
|
||||
if (renderer instanceof PolygonBatcher) {
|
||||
this.batcherShader.bind();
|
||||
this.batcherShader.setUniform4x4f(Shader.MVP_MATRIX, this.camera.projectionView.values);
|
||||
this.batcherShader.setUniformi("u_texture", 0);
|
||||
this.batcher.begin(this.batcherShader);
|
||||
this.activeRenderer = this.batcher;
|
||||
} else if (renderer instanceof ShapeRenderer) {
|
||||
this.shapesShader.bind();
|
||||
this.shapesShader.setUniform4x4f(Shader.MVP_MATRIX, this.camera.projectionView.values);
|
||||
this.shapes.begin(this.shapesShader);
|
||||
this.activeRenderer = this.shapes;
|
||||
} else
|
||||
this.activeRenderer = this.skeletonDebugRenderer;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.batcher.dispose();
|
||||
this.batcherShader.dispose();
|
||||
this.shapes.dispose();
|
||||
this.shapesShader.dispose();
|
||||
this.skeletonDebugRenderer.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export enum ResizeMode {
|
||||
Stretch,
|
||||
Expand,
|
||||
Fit
|
||||
}
|
||||
|
||||
@ -27,165 +27,167 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
export class Shader implements Disposable, Restorable {
|
||||
public static MVP_MATRIX = "u_projTrans";
|
||||
public static POSITION = "a_position";
|
||||
public static COLOR = "a_color";
|
||||
public static COLOR2 = "a_color2";
|
||||
public static TEXCOORDS = "a_texCoords";
|
||||
public static SAMPLER = "u_texture";
|
||||
import { Disposable, Restorable } from "spine-core";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL";
|
||||
|
||||
private context: ManagedWebGLRenderingContext;
|
||||
private vs: WebGLShader = null;
|
||||
private vsSource: string;
|
||||
private fs: WebGLShader = null;
|
||||
private fsSource: string;
|
||||
private program: WebGLProgram = null;
|
||||
private tmp2x2: Float32Array = new Float32Array(2 * 2);
|
||||
private tmp3x3: Float32Array = new Float32Array(3 * 3);
|
||||
private tmp4x4: Float32Array = new Float32Array(4 * 4);
|
||||
export class Shader implements Disposable, Restorable {
|
||||
public static MVP_MATRIX = "u_projTrans";
|
||||
public static POSITION = "a_position";
|
||||
public static COLOR = "a_color";
|
||||
public static COLOR2 = "a_color2";
|
||||
public static TEXCOORDS = "a_texCoords";
|
||||
public static SAMPLER = "u_texture";
|
||||
|
||||
public getProgram () { return this.program; }
|
||||
public getVertexShader () { return this.vertexShader; }
|
||||
public getFragmentShader () { return this.fragmentShader; }
|
||||
public getVertexShaderSource () { return this.vsSource; }
|
||||
public getFragmentSource () { return this.fsSource; }
|
||||
private context: ManagedWebGLRenderingContext;
|
||||
private vs: WebGLShader = null;
|
||||
private vsSource: string;
|
||||
private fs: WebGLShader = null;
|
||||
private fsSource: string;
|
||||
private program: WebGLProgram = null;
|
||||
private tmp2x2: Float32Array = new Float32Array(2 * 2);
|
||||
private tmp3x3: Float32Array = new Float32Array(3 * 3);
|
||||
private tmp4x4: Float32Array = new Float32Array(4 * 4);
|
||||
|
||||
constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext, private vertexShader: string, private fragmentShader: string) {
|
||||
this.vsSource = vertexShader;
|
||||
this.fsSource = fragmentShader;
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
this.context.addRestorable(this);
|
||||
this.compile();
|
||||
public getProgram() { return this.program; }
|
||||
public getVertexShader() { return this.vertexShader; }
|
||||
public getFragmentShader() { return this.fragmentShader; }
|
||||
public getVertexShaderSource() { return this.vsSource; }
|
||||
public getFragmentSource() { return this.fsSource; }
|
||||
|
||||
constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, private vertexShader: string, private fragmentShader: string) {
|
||||
this.vsSource = vertexShader;
|
||||
this.fsSource = fragmentShader;
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
this.context.addRestorable(this);
|
||||
this.compile();
|
||||
}
|
||||
|
||||
private compile() {
|
||||
let gl = this.context.gl;
|
||||
try {
|
||||
this.vs = this.compileShader(gl.VERTEX_SHADER, this.vertexShader);
|
||||
this.fs = this.compileShader(gl.FRAGMENT_SHADER, this.fragmentShader);
|
||||
this.program = this.compileProgram(this.vs, this.fs);
|
||||
} catch (e) {
|
||||
this.dispose();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private compileShader(type: number, source: string) {
|
||||
let gl = this.context.gl;
|
||||
let shader = gl.createShader(type);
|
||||
gl.shaderSource(shader, source);
|
||||
gl.compileShader(shader);
|
||||
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
||||
let error = "Couldn't compile shader: " + gl.getShaderInfoLog(shader);
|
||||
gl.deleteShader(shader);
|
||||
if (!gl.isContextLost()) throw new Error(error);
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
private compileProgram(vs: WebGLShader, fs: WebGLShader) {
|
||||
let gl = this.context.gl;
|
||||
let program = gl.createProgram();
|
||||
gl.attachShader(program, vs);
|
||||
gl.attachShader(program, fs);
|
||||
gl.linkProgram(program);
|
||||
|
||||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||||
let error = "Couldn't compile shader program: " + gl.getProgramInfoLog(program);
|
||||
gl.deleteProgram(program);
|
||||
if (!gl.isContextLost()) throw new Error(error);
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
restore() {
|
||||
this.compile();
|
||||
}
|
||||
|
||||
public bind() {
|
||||
this.context.gl.useProgram(this.program);
|
||||
}
|
||||
|
||||
public unbind() {
|
||||
this.context.gl.useProgram(null);
|
||||
}
|
||||
|
||||
public setUniformi(uniform: string, value: number) {
|
||||
this.context.gl.uniform1i(this.getUniformLocation(uniform), value);
|
||||
}
|
||||
|
||||
public setUniformf(uniform: string, value: number) {
|
||||
this.context.gl.uniform1f(this.getUniformLocation(uniform), value);
|
||||
}
|
||||
|
||||
public setUniform2f(uniform: string, value: number, value2: number) {
|
||||
this.context.gl.uniform2f(this.getUniformLocation(uniform), value, value2);
|
||||
}
|
||||
|
||||
public setUniform3f(uniform: string, value: number, value2: number, value3: number) {
|
||||
this.context.gl.uniform3f(this.getUniformLocation(uniform), value, value2, value3);
|
||||
}
|
||||
|
||||
public setUniform4f(uniform: string, value: number, value2: number, value3: number, value4: number) {
|
||||
this.context.gl.uniform4f(this.getUniformLocation(uniform), value, value2, value3, value4);
|
||||
}
|
||||
|
||||
public setUniform2x2f(uniform: string, value: ArrayLike<number>) {
|
||||
let gl = this.context.gl;
|
||||
this.tmp2x2.set(value);
|
||||
gl.uniformMatrix2fv(this.getUniformLocation(uniform), false, this.tmp2x2);
|
||||
}
|
||||
|
||||
public setUniform3x3f(uniform: string, value: ArrayLike<number>) {
|
||||
let gl = this.context.gl;
|
||||
this.tmp3x3.set(value);
|
||||
gl.uniformMatrix3fv(this.getUniformLocation(uniform), false, this.tmp3x3);
|
||||
}
|
||||
|
||||
public setUniform4x4f(uniform: string, value: ArrayLike<number>) {
|
||||
let gl = this.context.gl;
|
||||
this.tmp4x4.set(value);
|
||||
gl.uniformMatrix4fv(this.getUniformLocation(uniform), false, this.tmp4x4);
|
||||
}
|
||||
|
||||
public getUniformLocation(uniform: string): WebGLUniformLocation {
|
||||
let gl = this.context.gl;
|
||||
let location = gl.getUniformLocation(this.program, uniform);
|
||||
if (!location && !gl.isContextLost()) throw new Error(`Couldn't find location for uniform ${uniform}`);
|
||||
return location;
|
||||
}
|
||||
|
||||
public getAttributeLocation(attribute: string): number {
|
||||
let gl = this.context.gl;
|
||||
let location = gl.getAttribLocation(this.program, attribute);
|
||||
if (location == -1 && !gl.isContextLost()) throw new Error(`Couldn't find location for attribute ${attribute}`);
|
||||
return location;
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
this.context.removeRestorable(this);
|
||||
|
||||
let gl = this.context.gl;
|
||||
if (this.vs) {
|
||||
gl.deleteShader(this.vs);
|
||||
this.vs = null;
|
||||
}
|
||||
|
||||
private compile () {
|
||||
let gl = this.context.gl;
|
||||
try {
|
||||
this.vs = this.compileShader(gl.VERTEX_SHADER, this.vertexShader);
|
||||
this.fs = this.compileShader(gl.FRAGMENT_SHADER, this.fragmentShader);
|
||||
this.program = this.compileProgram(this.vs, this.fs);
|
||||
} catch (e) {
|
||||
this.dispose();
|
||||
throw e;
|
||||
}
|
||||
if (this.fs) {
|
||||
gl.deleteShader(this.fs);
|
||||
this.fs = null;
|
||||
}
|
||||
|
||||
private compileShader (type: number, source: string) {
|
||||
let gl = this.context.gl;
|
||||
let shader = gl.createShader(type);
|
||||
gl.shaderSource(shader, source);
|
||||
gl.compileShader(shader);
|
||||
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
||||
let error = "Couldn't compile shader: " + gl.getShaderInfoLog(shader);
|
||||
gl.deleteShader(shader);
|
||||
if (!gl.isContextLost()) throw new Error(error);
|
||||
}
|
||||
return shader;
|
||||
if (this.program) {
|
||||
gl.deleteProgram(this.program);
|
||||
this.program = null;
|
||||
}
|
||||
}
|
||||
|
||||
private compileProgram (vs: WebGLShader, fs: WebGLShader) {
|
||||
let gl = this.context.gl;
|
||||
let program = gl.createProgram();
|
||||
gl.attachShader(program, vs);
|
||||
gl.attachShader(program, fs);
|
||||
gl.linkProgram(program);
|
||||
|
||||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||||
let error = "Couldn't compile shader program: " + gl.getProgramInfoLog(program);
|
||||
gl.deleteProgram(program);
|
||||
if (!gl.isContextLost()) throw new Error(error);
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
restore () {
|
||||
this.compile();
|
||||
}
|
||||
|
||||
public bind () {
|
||||
this.context.gl.useProgram(this.program);
|
||||
}
|
||||
|
||||
public unbind () {
|
||||
this.context.gl.useProgram(null);
|
||||
}
|
||||
|
||||
public setUniformi (uniform: string, value: number) {
|
||||
this.context.gl.uniform1i(this.getUniformLocation(uniform), value);
|
||||
}
|
||||
|
||||
public setUniformf (uniform: string, value: number) {
|
||||
this.context.gl.uniform1f(this.getUniformLocation(uniform), value);
|
||||
}
|
||||
|
||||
public setUniform2f (uniform: string, value: number, value2: number) {
|
||||
this.context.gl.uniform2f(this.getUniformLocation(uniform), value, value2);
|
||||
}
|
||||
|
||||
public setUniform3f (uniform: string, value: number, value2: number, value3: number) {
|
||||
this.context.gl.uniform3f(this.getUniformLocation(uniform), value, value2, value3);
|
||||
}
|
||||
|
||||
public setUniform4f (uniform: string, value: number, value2: number, value3: number, value4: number) {
|
||||
this.context.gl.uniform4f(this.getUniformLocation(uniform), value, value2, value3, value4);
|
||||
}
|
||||
|
||||
public setUniform2x2f (uniform: string, value: ArrayLike<number>) {
|
||||
let gl = this.context.gl;
|
||||
this.tmp2x2.set(value);
|
||||
gl.uniformMatrix2fv(this.getUniformLocation(uniform), false, this.tmp2x2);
|
||||
}
|
||||
|
||||
public setUniform3x3f (uniform: string, value: ArrayLike<number>) {
|
||||
let gl = this.context.gl;
|
||||
this.tmp3x3.set(value);
|
||||
gl.uniformMatrix3fv(this.getUniformLocation(uniform), false, this.tmp3x3);
|
||||
}
|
||||
|
||||
public setUniform4x4f (uniform: string, value: ArrayLike<number>) {
|
||||
let gl = this.context.gl;
|
||||
this.tmp4x4.set(value);
|
||||
gl.uniformMatrix4fv(this.getUniformLocation(uniform), false, this.tmp4x4);
|
||||
}
|
||||
|
||||
public getUniformLocation (uniform: string): WebGLUniformLocation {
|
||||
let gl = this.context.gl;
|
||||
let location = gl.getUniformLocation(this.program, uniform);
|
||||
if (!location && !gl.isContextLost()) throw new Error(`Couldn't find location for uniform ${uniform}`);
|
||||
return location;
|
||||
}
|
||||
|
||||
public getAttributeLocation (attribute: string): number {
|
||||
let gl = this.context.gl;
|
||||
let location = gl.getAttribLocation(this.program, attribute);
|
||||
if (location == -1 && !gl.isContextLost()) throw new Error(`Couldn't find location for attribute ${attribute}`);
|
||||
return location;
|
||||
}
|
||||
|
||||
public dispose () {
|
||||
this.context.removeRestorable(this);
|
||||
|
||||
let gl = this.context.gl;
|
||||
if (this.vs) {
|
||||
gl.deleteShader(this.vs);
|
||||
this.vs = null;
|
||||
}
|
||||
|
||||
if (this.fs) {
|
||||
gl.deleteShader(this.fs);
|
||||
this.fs = null;
|
||||
}
|
||||
|
||||
if (this.program) {
|
||||
gl.deleteProgram(this.program);
|
||||
this.program = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static newColoredTextured (context: ManagedWebGLRenderingContext | WebGLRenderingContext): Shader {
|
||||
let vs = `
|
||||
public static newColoredTextured(context: ManagedWebGLRenderingContext | WebGLRenderingContext): Shader {
|
||||
let vs = `
|
||||
attribute vec4 ${Shader.POSITION};
|
||||
attribute vec4 ${Shader.COLOR};
|
||||
attribute vec2 ${Shader.TEXCOORDS};
|
||||
@ -200,7 +202,7 @@ module spine.webgl {
|
||||
}
|
||||
`;
|
||||
|
||||
let fs = `
|
||||
let fs = `
|
||||
#ifdef GL_ES
|
||||
#define LOWP lowp
|
||||
precision mediump float;
|
||||
@ -216,11 +218,11 @@ module spine.webgl {
|
||||
}
|
||||
`;
|
||||
|
||||
return new Shader(context, vs, fs);
|
||||
}
|
||||
return new Shader(context, vs, fs);
|
||||
}
|
||||
|
||||
public static newTwoColoredTextured (context: ManagedWebGLRenderingContext | WebGLRenderingContext): Shader {
|
||||
let vs = `
|
||||
public static newTwoColoredTextured(context: ManagedWebGLRenderingContext | WebGLRenderingContext): Shader {
|
||||
let vs = `
|
||||
attribute vec4 ${Shader.POSITION};
|
||||
attribute vec4 ${Shader.COLOR};
|
||||
attribute vec4 ${Shader.COLOR2};
|
||||
@ -238,7 +240,7 @@ module spine.webgl {
|
||||
}
|
||||
`;
|
||||
|
||||
let fs = `
|
||||
let fs = `
|
||||
#ifdef GL_ES
|
||||
#define LOWP lowp
|
||||
precision mediump float;
|
||||
@ -257,11 +259,11 @@ module spine.webgl {
|
||||
}
|
||||
`;
|
||||
|
||||
return new Shader(context, vs, fs);
|
||||
}
|
||||
return new Shader(context, vs, fs);
|
||||
}
|
||||
|
||||
public static newColored (context: ManagedWebGLRenderingContext | WebGLRenderingContext): Shader {
|
||||
let vs = `
|
||||
public static newColored(context: ManagedWebGLRenderingContext | WebGLRenderingContext): Shader {
|
||||
let vs = `
|
||||
attribute vec4 ${Shader.POSITION};
|
||||
attribute vec4 ${Shader.COLOR};
|
||||
uniform mat4 ${Shader.MVP_MATRIX};
|
||||
@ -273,7 +275,7 @@ module spine.webgl {
|
||||
}
|
||||
`;
|
||||
|
||||
let fs = `
|
||||
let fs = `
|
||||
#ifdef GL_ES
|
||||
#define LOWP lowp
|
||||
precision mediump float;
|
||||
@ -287,7 +289,6 @@ module spine.webgl {
|
||||
}
|
||||
`;
|
||||
|
||||
return new Shader(context, vs, fs);
|
||||
}
|
||||
return new Shader(context, vs, fs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,323 +27,326 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
export class ShapeRenderer implements Disposable {
|
||||
private context: ManagedWebGLRenderingContext;
|
||||
private isDrawing = false;
|
||||
private mesh: Mesh;
|
||||
private shapeType = ShapeType.Filled;
|
||||
private color = new Color(1, 1, 1, 1);
|
||||
private shader: Shader;
|
||||
private vertexIndex = 0;
|
||||
private tmp = new Vector2();
|
||||
private srcColorBlend: number;
|
||||
private srcAlphaBlend: number;
|
||||
private dstBlend: number;
|
||||
import { Disposable, Color, Vector2, MathUtils } from "spine-core";
|
||||
import { Mesh, Position2Attribute, ColorAttribute } from "./Mesh";
|
||||
import { Shader } from "./Shader";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL";
|
||||
|
||||
constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext, maxVertices: number = 10920) {
|
||||
if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
this.mesh = new Mesh(context, [new Position2Attribute(), new ColorAttribute()], maxVertices, 0);
|
||||
export class ShapeRenderer implements Disposable {
|
||||
private context: ManagedWebGLRenderingContext;
|
||||
private isDrawing = false;
|
||||
private mesh: Mesh;
|
||||
private shapeType = ShapeType.Filled;
|
||||
private color = new Color(1, 1, 1, 1);
|
||||
private shader: Shader;
|
||||
private vertexIndex = 0;
|
||||
private tmp = new Vector2();
|
||||
private srcColorBlend: number;
|
||||
private srcAlphaBlend: number;
|
||||
private dstBlend: number;
|
||||
|
||||
constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, maxVertices: number = 10920) {
|
||||
if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
this.mesh = new Mesh(context, [new Position2Attribute(), new ColorAttribute()], maxVertices, 0);
|
||||
let gl = this.context.gl;
|
||||
this.srcColorBlend = gl.SRC_ALPHA;
|
||||
this.srcAlphaBlend = gl.ONE;
|
||||
this.dstBlend = gl.ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
|
||||
begin(shader: Shader) {
|
||||
if (this.isDrawing) throw new Error("ShapeRenderer.begin() has already been called");
|
||||
this.shader = shader;
|
||||
this.vertexIndex = 0;
|
||||
this.isDrawing = true;
|
||||
|
||||
let gl = this.context.gl;
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendFuncSeparate(this.srcColorBlend, this.dstBlend, this.srcAlphaBlend, this.dstBlend);
|
||||
}
|
||||
|
||||
setBlendMode(srcColorBlend: number, srcAlphaBlend: number, dstBlend: number) {
|
||||
this.srcColorBlend = srcColorBlend;
|
||||
this.srcAlphaBlend = srcAlphaBlend;
|
||||
this.dstBlend = dstBlend;
|
||||
if (this.isDrawing) {
|
||||
this.flush();
|
||||
let gl = this.context.gl;
|
||||
this.srcColorBlend = gl.SRC_ALPHA;
|
||||
this.srcAlphaBlend = gl.ONE;
|
||||
this.dstBlend = gl.ONE_MINUS_SRC_ALPHA;
|
||||
gl.blendFuncSeparate(srcColorBlend, dstBlend, srcAlphaBlend, dstBlend);
|
||||
}
|
||||
}
|
||||
|
||||
begin (shader: Shader) {
|
||||
if (this.isDrawing) throw new Error("ShapeRenderer.begin() has already been called");
|
||||
this.shader = shader;
|
||||
this.vertexIndex = 0;
|
||||
this.isDrawing = true;
|
||||
setColor(color: Color) {
|
||||
this.color.setFromColor(color);
|
||||
}
|
||||
|
||||
let gl = this.context.gl;
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendFuncSeparate(this.srcColorBlend, this.dstBlend, this.srcAlphaBlend, this.dstBlend);
|
||||
setColorWith(r: number, g: number, b: number, a: number) {
|
||||
this.color.set(r, g, b, a);
|
||||
}
|
||||
|
||||
point(x: number, y: number, color: Color = null) {
|
||||
this.check(ShapeType.Point, 1);
|
||||
if (color === null) color = this.color;
|
||||
this.vertex(x, y, color);
|
||||
}
|
||||
|
||||
line(x: number, y: number, x2: number, y2: number, color: Color = null) {
|
||||
this.check(ShapeType.Line, 2);
|
||||
let vertices = this.mesh.getVertices();
|
||||
let idx = this.vertexIndex;
|
||||
if (color === null) color = this.color;
|
||||
this.vertex(x, y, color);
|
||||
this.vertex(x2, y2, color);
|
||||
}
|
||||
|
||||
triangle(filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, color: Color = null, color2: Color = null, color3: Color = null) {
|
||||
this.check(filled ? ShapeType.Filled : ShapeType.Line, 3);
|
||||
let vertices = this.mesh.getVertices();
|
||||
let idx = this.vertexIndex;
|
||||
if (color === null) color = this.color;
|
||||
if (color2 === null) color2 = this.color;
|
||||
if (color3 === null) color3 = this.color;
|
||||
if (filled) {
|
||||
this.vertex(x, y, color);
|
||||
this.vertex(x2, y2, color2);
|
||||
this.vertex(x3, y3, color3);
|
||||
} else {
|
||||
this.vertex(x, y, color);
|
||||
this.vertex(x2, y2, color2);
|
||||
|
||||
this.vertex(x2, y2, color);
|
||||
this.vertex(x3, y3, color2);
|
||||
|
||||
this.vertex(x3, y3, color);
|
||||
this.vertex(x, y, color2);
|
||||
}
|
||||
}
|
||||
|
||||
setBlendMode (srcColorBlend: number, srcAlphaBlend: number, dstBlend: number) {
|
||||
this.srcColorBlend = srcColorBlend;
|
||||
this.srcAlphaBlend = srcAlphaBlend;
|
||||
this.dstBlend = dstBlend;
|
||||
if (this.isDrawing) {
|
||||
this.flush();
|
||||
let gl = this.context.gl;
|
||||
gl.blendFuncSeparate(srcColorBlend, dstBlend, srcAlphaBlend, dstBlend);
|
||||
quad(filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, color: Color = null, color2: Color = null, color3: Color = null, color4: Color = null) {
|
||||
this.check(filled ? ShapeType.Filled : ShapeType.Line, 3);
|
||||
let vertices = this.mesh.getVertices();
|
||||
let idx = this.vertexIndex;
|
||||
if (color === null) color = this.color;
|
||||
if (color2 === null) color2 = this.color;
|
||||
if (color3 === null) color3 = this.color;
|
||||
if (color4 === null) color4 = this.color;
|
||||
if (filled) {
|
||||
this.vertex(x, y, color); this.vertex(x2, y2, color2); this.vertex(x3, y3, color3);
|
||||
this.vertex(x3, y3, color3); this.vertex(x4, y4, color4); this.vertex(x, y, color);
|
||||
} else {
|
||||
this.vertex(x, y, color); this.vertex(x2, y2, color2);
|
||||
this.vertex(x2, y2, color2); this.vertex(x3, y3, color3);
|
||||
this.vertex(x3, y3, color3); this.vertex(x4, y4, color4);
|
||||
this.vertex(x4, y4, color4); this.vertex(x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
rect(filled: boolean, x: number, y: number, width: number, height: number, color: Color = null) {
|
||||
this.quad(filled, x, y, x + width, y, x + width, y + height, x, y + height, color, color, color, color);
|
||||
}
|
||||
|
||||
rectLine(filled: boolean, x1: number, y1: number, x2: number, y2: number, width: number, color: Color = null) {
|
||||
this.check(filled ? ShapeType.Filled : ShapeType.Line, 8);
|
||||
if (color === null) color = this.color;
|
||||
let t = this.tmp.set(y2 - y1, x1 - x2);
|
||||
t.normalize();
|
||||
width *= 0.5;
|
||||
let tx = t.x * width;
|
||||
let ty = t.y * width;
|
||||
if (!filled) {
|
||||
this.vertex(x1 + tx, y1 + ty, color);
|
||||
this.vertex(x1 - tx, y1 - ty, color);
|
||||
this.vertex(x2 + tx, y2 + ty, color);
|
||||
this.vertex(x2 - tx, y2 - ty, color);
|
||||
|
||||
this.vertex(x2 + tx, y2 + ty, color);
|
||||
this.vertex(x1 + tx, y1 + ty, color);
|
||||
|
||||
this.vertex(x2 - tx, y2 - ty, color);
|
||||
this.vertex(x1 - tx, y1 - ty, color);
|
||||
} else {
|
||||
this.vertex(x1 + tx, y1 + ty, color);
|
||||
this.vertex(x1 - tx, y1 - ty, color);
|
||||
this.vertex(x2 + tx, y2 + ty, color);
|
||||
|
||||
this.vertex(x2 - tx, y2 - ty, color);
|
||||
this.vertex(x2 + tx, y2 + ty, color);
|
||||
this.vertex(x1 - tx, y1 - ty, color);
|
||||
}
|
||||
}
|
||||
|
||||
x(x: number, y: number, size: number) {
|
||||
this.line(x - size, y - size, x + size, y + size);
|
||||
this.line(x - size, y + size, x + size, y - size);
|
||||
}
|
||||
|
||||
polygon(polygonVertices: ArrayLike<number>, offset: number, count: number, color: Color = null) {
|
||||
if (count < 3) throw new Error("Polygon must contain at least 3 vertices");
|
||||
this.check(ShapeType.Line, count * 2);
|
||||
if (color === null) color = this.color;
|
||||
let vertices = this.mesh.getVertices();
|
||||
let idx = this.vertexIndex;
|
||||
|
||||
offset <<= 1;
|
||||
count <<= 1;
|
||||
|
||||
let firstX = polygonVertices[offset];
|
||||
let firstY = polygonVertices[offset + 1];
|
||||
let last = offset + count;
|
||||
|
||||
for (let i = offset, n = offset + count - 2; i < n; i += 2) {
|
||||
let x1 = polygonVertices[i];
|
||||
let y1 = polygonVertices[i + 1];
|
||||
|
||||
let x2 = 0;
|
||||
let y2 = 0;
|
||||
|
||||
if (i + 2 >= last) {
|
||||
x2 = firstX;
|
||||
y2 = firstY;
|
||||
} else {
|
||||
x2 = polygonVertices[i + 2];
|
||||
y2 = polygonVertices[i + 3];
|
||||
}
|
||||
}
|
||||
|
||||
setColor (color: Color) {
|
||||
this.color.setFromColor(color);
|
||||
}
|
||||
|
||||
setColorWith (r: number, g: number, b: number, a: number) {
|
||||
this.color.set(r, g, b, a);
|
||||
}
|
||||
|
||||
point (x: number, y: number, color: Color = null) {
|
||||
this.check(ShapeType.Point, 1);
|
||||
if (color === null) color = this.color;
|
||||
this.vertex(x, y, color);
|
||||
}
|
||||
|
||||
line (x: number, y: number, x2: number, y2: number, color: Color = null) {
|
||||
this.check(ShapeType.Line, 2);
|
||||
let vertices = this.mesh.getVertices();
|
||||
let idx = this.vertexIndex;
|
||||
if (color === null) color = this.color;
|
||||
this.vertex(x, y, color);
|
||||
this.vertex(x1, y1, color);
|
||||
this.vertex(x2, y2, color);
|
||||
}
|
||||
}
|
||||
|
||||
triangle (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, color: Color = null, color2: Color = null, color3: Color = null) {
|
||||
this.check(filled ? ShapeType.Filled : ShapeType.Line, 3);
|
||||
let vertices = this.mesh.getVertices();
|
||||
let idx = this.vertexIndex;
|
||||
if (color === null) color = this.color;
|
||||
if (color2 === null) color2 = this.color;
|
||||
if (color3 === null) color3 = this.color;
|
||||
if (filled) {
|
||||
this.vertex(x, y, color);
|
||||
this.vertex(x2, y2, color2);
|
||||
this.vertex(x3, y3, color3);
|
||||
} else {
|
||||
this.vertex(x, y, color);
|
||||
this.vertex(x2, y2, color2);
|
||||
|
||||
this.vertex(x2, y2, color);
|
||||
this.vertex(x3, y3, color2);
|
||||
|
||||
this.vertex(x3, y3, color);
|
||||
this.vertex(x, y, color2);
|
||||
}
|
||||
}
|
||||
|
||||
quad (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, color: Color = null, color2: Color = null, color3: Color = null, color4: Color = null) {
|
||||
this.check(filled ? ShapeType.Filled : ShapeType.Line, 3);
|
||||
let vertices = this.mesh.getVertices();
|
||||
let idx = this.vertexIndex;
|
||||
if (color === null) color = this.color;
|
||||
if (color2 === null) color2 = this.color;
|
||||
if (color3 === null) color3 = this.color;
|
||||
if (color4 === null) color4 = this.color;
|
||||
if (filled) {
|
||||
this.vertex(x, y, color); this.vertex(x2, y2, color2); this.vertex(x3, y3, color3);
|
||||
this.vertex(x3, y3, color3); this.vertex(x4, y4, color4); this.vertex(x, y, color);
|
||||
} else {
|
||||
this.vertex(x, y, color); this.vertex(x2, y2, color2);
|
||||
this.vertex(x2, y2, color2); this.vertex(x3, y3, color3);
|
||||
this.vertex(x3, y3, color3); this.vertex(x4, y4, color4);
|
||||
this.vertex(x4, y4, color4); this.vertex(x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
rect (filled: boolean, x: number, y: number, width: number, height: number, color: Color = null) {
|
||||
this.quad(filled, x, y, x + width, y, x + width, y + height, x, y + height, color, color, color, color);
|
||||
}
|
||||
|
||||
rectLine (filled: boolean, x1: number, y1: number, x2: number, y2: number, width: number, color: Color = null) {
|
||||
this.check(filled ? ShapeType.Filled : ShapeType.Line, 8);
|
||||
if (color === null) color = this.color;
|
||||
let t = this.tmp.set(y2 - y1, x1 - x2);
|
||||
t.normalize();
|
||||
width *= 0.5;
|
||||
let tx = t.x * width;
|
||||
let ty = t.y * width;
|
||||
if (!filled) {
|
||||
this.vertex(x1 + tx, y1 + ty, color);
|
||||
this.vertex(x1 - tx, y1 - ty, color);
|
||||
this.vertex(x2 + tx, y2 + ty, color);
|
||||
this.vertex(x2 - tx, y2 - ty, color);
|
||||
|
||||
this.vertex(x2 + tx, y2 + ty, color);
|
||||
this.vertex(x1 + tx, y1 + ty, color);
|
||||
|
||||
this.vertex(x2 - tx, y2 - ty, color);
|
||||
this.vertex(x1 - tx, y1 - ty, color);
|
||||
} else {
|
||||
this.vertex(x1 + tx, y1 + ty, color);
|
||||
this.vertex(x1 - tx, y1 - ty, color);
|
||||
this.vertex(x2 + tx, y2 + ty, color);
|
||||
|
||||
this.vertex(x2 - tx, y2 - ty, color);
|
||||
this.vertex(x2 + tx, y2 + ty, color);
|
||||
this.vertex(x1 - tx, y1 - ty, color);
|
||||
}
|
||||
}
|
||||
|
||||
x (x: number, y: number, size: number) {
|
||||
this.line(x - size, y - size, x + size, y + size);
|
||||
this.line(x - size, y + size, x + size, y - size);
|
||||
}
|
||||
|
||||
polygon (polygonVertices: ArrayLike<number>, offset: number, count: number, color: Color = null) {
|
||||
if (count < 3) throw new Error("Polygon must contain at least 3 vertices");
|
||||
this.check(ShapeType.Line, count * 2);
|
||||
if (color === null) color = this.color;
|
||||
let vertices = this.mesh.getVertices();
|
||||
let idx = this.vertexIndex;
|
||||
|
||||
offset <<= 1;
|
||||
count <<= 1;
|
||||
|
||||
let firstX = polygonVertices[offset];
|
||||
let firstY = polygonVertices[offset + 1];
|
||||
let last = offset + count;
|
||||
|
||||
for (let i = offset, n = offset + count - 2; i < n; i += 2) {
|
||||
let x1 = polygonVertices[i];
|
||||
let y1 = polygonVertices[i + 1];
|
||||
|
||||
let x2 = 0;
|
||||
let y2 = 0;
|
||||
|
||||
if (i + 2 >= last) {
|
||||
x2 = firstX;
|
||||
y2 = firstY;
|
||||
} else {
|
||||
x2 = polygonVertices[i + 2];
|
||||
y2 = polygonVertices[i + 3];
|
||||
}
|
||||
|
||||
this.vertex(x1, y1, color);
|
||||
this.vertex(x2, y2, color);
|
||||
}
|
||||
}
|
||||
|
||||
circle (filled: boolean, x: number, y: number, radius: number, color: Color = null, segments: number = 0) {
|
||||
if (segments === 0) segments = Math.max(1, (6 * MathUtils.cbrt(radius)) | 0);
|
||||
if (segments <= 0) throw new Error("segments must be > 0.");
|
||||
if (color === null) color = this.color;
|
||||
let angle = 2 * MathUtils.PI / segments;
|
||||
let cos = Math.cos(angle);
|
||||
let sin = Math.sin(angle);
|
||||
let cx = radius, cy = 0;
|
||||
if (!filled) {
|
||||
this.check(ShapeType.Line, segments * 2 + 2);
|
||||
for (let i = 0; i < segments; i++) {
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
let temp = cx;
|
||||
cx = cos * cx - sin * cy;
|
||||
cy = sin * temp + cos * cy;
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
}
|
||||
// Ensure the last segment is identical to the first.
|
||||
circle(filled: boolean, x: number, y: number, radius: number, color: Color = null, segments: number = 0) {
|
||||
if (segments === 0) segments = Math.max(1, (6 * MathUtils.cbrt(radius)) | 0);
|
||||
if (segments <= 0) throw new Error("segments must be > 0.");
|
||||
if (color === null) color = this.color;
|
||||
let angle = 2 * MathUtils.PI / segments;
|
||||
let cos = Math.cos(angle);
|
||||
let sin = Math.sin(angle);
|
||||
let cx = radius, cy = 0;
|
||||
if (!filled) {
|
||||
this.check(ShapeType.Line, segments * 2 + 2);
|
||||
for (let i = 0; i < segments; i++) {
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
} else {
|
||||
this.check(ShapeType.Filled, segments * 3 + 3);
|
||||
segments--;
|
||||
for (let i = 0; i < segments; i++) {
|
||||
this.vertex(x, y, color);
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
let temp = cx;
|
||||
cx = cos * cx - sin * cy;
|
||||
cy = sin * temp + cos * cy;
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
}
|
||||
// Ensure the last segment is identical to the first.
|
||||
this.vertex(x, y, color);
|
||||
let temp = cx;
|
||||
cx = cos * cx - sin * cy;
|
||||
cy = sin * temp + cos * cy;
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
}
|
||||
|
||||
let temp = cx;
|
||||
cx = radius;
|
||||
cy = 0;
|
||||
// Ensure the last segment is identical to the first.
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
} else {
|
||||
this.check(ShapeType.Filled, segments * 3 + 3);
|
||||
segments--;
|
||||
for (let i = 0; i < segments; i++) {
|
||||
this.vertex(x, y, color);
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
let temp = cx;
|
||||
cx = cos * cx - sin * cy;
|
||||
cy = sin * temp + cos * cy;
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
}
|
||||
// Ensure the last segment is identical to the first.
|
||||
this.vertex(x, y, color);
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
}
|
||||
|
||||
curve (x1: number, y1: number, cx1: number, cy1: number, cx2: number, cy2: number, x2: number, y2: number, segments: number, color: Color = null) {
|
||||
this.check(ShapeType.Line, segments * 2 + 2);
|
||||
if (color === null) color = this.color;
|
||||
let temp = cx;
|
||||
cx = radius;
|
||||
cy = 0;
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
}
|
||||
|
||||
// Algorithm from: http://www.antigrain.com/research/bezier_interpolation/index.html#PAGE_BEZIER_INTERPOLATION
|
||||
let subdiv_step = 1 / segments;
|
||||
let subdiv_step2 = subdiv_step * subdiv_step;
|
||||
let subdiv_step3 = subdiv_step * subdiv_step * subdiv_step;
|
||||
curve(x1: number, y1: number, cx1: number, cy1: number, cx2: number, cy2: number, x2: number, y2: number, segments: number, color: Color = null) {
|
||||
this.check(ShapeType.Line, segments * 2 + 2);
|
||||
if (color === null) color = this.color;
|
||||
|
||||
let pre1 = 3 * subdiv_step;
|
||||
let pre2 = 3 * subdiv_step2;
|
||||
let pre4 = 6 * subdiv_step2;
|
||||
let pre5 = 6 * subdiv_step3;
|
||||
// Algorithm from: http://www.antigrain.com/research/bezier_interpolation/index.html#PAGE_BEZIER_INTERPOLATION
|
||||
let subdiv_step = 1 / segments;
|
||||
let subdiv_step2 = subdiv_step * subdiv_step;
|
||||
let subdiv_step3 = subdiv_step * subdiv_step * subdiv_step;
|
||||
|
||||
let tmp1x = x1 - cx1 * 2 + cx2;
|
||||
let tmp1y = y1 - cy1 * 2 + cy2;
|
||||
let pre1 = 3 * subdiv_step;
|
||||
let pre2 = 3 * subdiv_step2;
|
||||
let pre4 = 6 * subdiv_step2;
|
||||
let pre5 = 6 * subdiv_step3;
|
||||
|
||||
let tmp2x = (cx1 - cx2) * 3 - x1 + x2;
|
||||
let tmp2y = (cy1 - cy2) * 3 - y1 + y2;
|
||||
let tmp1x = x1 - cx1 * 2 + cx2;
|
||||
let tmp1y = y1 - cy1 * 2 + cy2;
|
||||
|
||||
let fx = x1;
|
||||
let fy = y1;
|
||||
let tmp2x = (cx1 - cx2) * 3 - x1 + x2;
|
||||
let tmp2y = (cy1 - cy2) * 3 - y1 + y2;
|
||||
|
||||
let dfx = (cx1 - x1) * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3;
|
||||
let dfy = (cy1 - y1) * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3;
|
||||
let fx = x1;
|
||||
let fy = y1;
|
||||
|
||||
let ddfx = tmp1x * pre4 + tmp2x * pre5;
|
||||
let ddfy = tmp1y * pre4 + tmp2y * pre5;
|
||||
let dfx = (cx1 - x1) * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3;
|
||||
let dfy = (cy1 - y1) * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3;
|
||||
|
||||
let dddfx = tmp2x * pre5;
|
||||
let dddfy = tmp2y * pre5;
|
||||
let ddfx = tmp1x * pre4 + tmp2x * pre5;
|
||||
let ddfy = tmp1y * pre4 + tmp2y * pre5;
|
||||
|
||||
while (segments-- > 0) {
|
||||
this.vertex(fx, fy, color);
|
||||
fx += dfx;
|
||||
fy += dfy;
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
ddfx += dddfx;
|
||||
ddfy += dddfy;
|
||||
this.vertex(fx, fy, color);
|
||||
}
|
||||
let dddfx = tmp2x * pre5;
|
||||
let dddfy = tmp2y * pre5;
|
||||
|
||||
while (segments-- > 0) {
|
||||
this.vertex(fx, fy, color);
|
||||
fx += dfx;
|
||||
fy += dfy;
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
ddfx += dddfx;
|
||||
ddfy += dddfy;
|
||||
this.vertex(fx, fy, color);
|
||||
this.vertex(x2, y2, color);
|
||||
}
|
||||
this.vertex(fx, fy, color);
|
||||
this.vertex(x2, y2, color);
|
||||
}
|
||||
|
||||
private vertex (x: number, y: number, color: Color) {
|
||||
let idx = this.vertexIndex;
|
||||
let vertices = this.mesh.getVertices();
|
||||
vertices[idx++] = x;
|
||||
vertices[idx++] = y;
|
||||
vertices[idx++] = color.r;
|
||||
vertices[idx++] = color.g;
|
||||
vertices[idx++] = color.b;
|
||||
vertices[idx++] = color.a;
|
||||
this.vertexIndex = idx;
|
||||
}
|
||||
private vertex(x: number, y: number, color: Color) {
|
||||
let idx = this.vertexIndex;
|
||||
let vertices = this.mesh.getVertices();
|
||||
vertices[idx++] = x;
|
||||
vertices[idx++] = y;
|
||||
vertices[idx++] = color.r;
|
||||
vertices[idx++] = color.g;
|
||||
vertices[idx++] = color.b;
|
||||
vertices[idx++] = color.a;
|
||||
this.vertexIndex = idx;
|
||||
}
|
||||
|
||||
end () {
|
||||
if (!this.isDrawing) throw new Error("ShapeRenderer.begin() has not been called");
|
||||
end() {
|
||||
if (!this.isDrawing) throw new Error("ShapeRenderer.begin() has not been called");
|
||||
this.flush();
|
||||
let gl = this.context.gl;
|
||||
gl.disable(gl.BLEND);
|
||||
this.isDrawing = false;
|
||||
}
|
||||
|
||||
private flush() {
|
||||
if (this.vertexIndex == 0) return;
|
||||
this.mesh.setVerticesLength(this.vertexIndex);
|
||||
this.mesh.draw(this.shader, this.shapeType);
|
||||
this.vertexIndex = 0;
|
||||
}
|
||||
|
||||
private check(shapeType: ShapeType, numVertices: number) {
|
||||
if (!this.isDrawing) throw new Error("ShapeRenderer.begin() has not been called");
|
||||
if (this.shapeType == shapeType) {
|
||||
if (this.mesh.maxVertices() - this.mesh.numVertices() < numVertices) this.flush();
|
||||
else return;
|
||||
} else {
|
||||
this.flush();
|
||||
let gl = this.context.gl;
|
||||
gl.disable(gl.BLEND);
|
||||
this.isDrawing = false;
|
||||
}
|
||||
|
||||
private flush () {
|
||||
if (this.vertexIndex == 0) return;
|
||||
this.mesh.setVerticesLength(this.vertexIndex);
|
||||
this.mesh.draw(this.shader, this.shapeType);
|
||||
this.vertexIndex = 0;
|
||||
}
|
||||
|
||||
private check (shapeType: ShapeType, numVertices: number) {
|
||||
if (!this.isDrawing) throw new Error("ShapeRenderer.begin() has not been called");
|
||||
if (this.shapeType == shapeType) {
|
||||
if (this.mesh.maxVertices() - this.mesh.numVertices() < numVertices) this.flush();
|
||||
else return;
|
||||
} else {
|
||||
this.flush();
|
||||
this.shapeType = shapeType;
|
||||
}
|
||||
}
|
||||
|
||||
dispose () {
|
||||
this.mesh.dispose();
|
||||
this.shapeType = shapeType;
|
||||
}
|
||||
}
|
||||
|
||||
export enum ShapeType {
|
||||
Point = 0x0000,
|
||||
Line = 0x0001,
|
||||
Filled = 0x0004
|
||||
dispose() {
|
||||
this.mesh.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export enum ShapeType {
|
||||
Point = 0x0000,
|
||||
Line = 0x0001,
|
||||
Filled = 0x0004
|
||||
}
|
||||
@ -27,199 +27,201 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
export class SkeletonDebugRenderer implements Disposable {
|
||||
boneLineColor = new Color(1, 0, 0, 1);
|
||||
boneOriginColor = new Color(0, 1, 0, 1);
|
||||
attachmentLineColor = new Color(0, 0, 1, 0.5);
|
||||
triangleLineColor = new Color(1, 0.64, 0, 0.5);
|
||||
pathColor = new Color().setFromString("FF7F00");
|
||||
clipColor = new Color(0.8, 0, 0, 2);
|
||||
aabbColor = new Color(0, 1, 0, 0.5);
|
||||
drawBones = true;
|
||||
drawRegionAttachments = true;
|
||||
drawBoundingBoxes = true;
|
||||
drawMeshHull = true;
|
||||
drawMeshTriangles = true;
|
||||
drawPaths = true;
|
||||
drawSkeletonXY = false;
|
||||
drawClipping = true;
|
||||
premultipliedAlpha = false;
|
||||
scale = 1;
|
||||
boneWidth = 2;
|
||||
import { Disposable, Color, SkeletonBounds, Utils, Skeleton, RegionAttachment, MeshAttachment, PathAttachment, ClippingAttachment } from "spine-core";
|
||||
import { ShapeRenderer } from "./ShapeRenderer";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL";
|
||||
|
||||
private context: ManagedWebGLRenderingContext;
|
||||
private bounds = new SkeletonBounds();
|
||||
private temp = new Array<number>();
|
||||
private vertices = Utils.newFloatArray(2 * 1024);
|
||||
private static LIGHT_GRAY = new Color(192 / 255, 192 / 255, 192 / 255, 1);
|
||||
private static GREEN = new Color(0, 1, 0, 1);
|
||||
export class SkeletonDebugRenderer implements Disposable {
|
||||
boneLineColor = new Color(1, 0, 0, 1);
|
||||
boneOriginColor = new Color(0, 1, 0, 1);
|
||||
attachmentLineColor = new Color(0, 0, 1, 0.5);
|
||||
triangleLineColor = new Color(1, 0.64, 0, 0.5);
|
||||
pathColor = new Color().setFromString("FF7F00");
|
||||
clipColor = new Color(0.8, 0, 0, 2);
|
||||
aabbColor = new Color(0, 1, 0, 0.5);
|
||||
drawBones = true;
|
||||
drawRegionAttachments = true;
|
||||
drawBoundingBoxes = true;
|
||||
drawMeshHull = true;
|
||||
drawMeshTriangles = true;
|
||||
drawPaths = true;
|
||||
drawSkeletonXY = false;
|
||||
drawClipping = true;
|
||||
premultipliedAlpha = false;
|
||||
scale = 1;
|
||||
boneWidth = 2;
|
||||
|
||||
constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext) {
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
private context: ManagedWebGLRenderingContext;
|
||||
private bounds = new SkeletonBounds();
|
||||
private temp = new Array<number>();
|
||||
private vertices = Utils.newFloatArray(2 * 1024);
|
||||
private static LIGHT_GRAY = new Color(192 / 255, 192 / 255, 192 / 255, 1);
|
||||
private static GREEN = new Color(0, 1, 0, 1);
|
||||
|
||||
constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext) {
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
}
|
||||
|
||||
draw(shapes: ShapeRenderer, skeleton: Skeleton, ignoredBones: Array<string> = null) {
|
||||
let skeletonX = skeleton.x;
|
||||
let skeletonY = skeleton.y;
|
||||
let gl = this.context.gl;
|
||||
let srcFunc = this.premultipliedAlpha ? gl.ONE : gl.SRC_ALPHA;
|
||||
shapes.setBlendMode(srcFunc, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
let bones = skeleton.bones;
|
||||
if (this.drawBones) {
|
||||
shapes.setColor(this.boneLineColor);
|
||||
for (let i = 0, n = bones.length; i < n; i++) {
|
||||
let bone = bones[i];
|
||||
if (ignoredBones && ignoredBones.indexOf(bone.data.name) > -1) continue;
|
||||
if (!bone.parent) continue;
|
||||
let x = skeletonX + bone.data.length * bone.a + bone.worldX;
|
||||
let y = skeletonY + bone.data.length * bone.c + bone.worldY;
|
||||
shapes.rectLine(true, skeletonX + bone.worldX, skeletonY + bone.worldY, x, y, this.boneWidth * this.scale);
|
||||
}
|
||||
if (this.drawSkeletonXY) shapes.x(skeletonX, skeletonY, 4 * this.scale);
|
||||
}
|
||||
|
||||
draw (shapes: ShapeRenderer, skeleton: Skeleton, ignoredBones: Array<string> = null) {
|
||||
let skeletonX = skeleton.x;
|
||||
let skeletonY = skeleton.y;
|
||||
let gl = this.context.gl;
|
||||
let srcFunc = this.premultipliedAlpha ? gl.ONE : gl.SRC_ALPHA;
|
||||
shapes.setBlendMode(srcFunc, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
let bones = skeleton.bones;
|
||||
if (this.drawBones) {
|
||||
shapes.setColor(this.boneLineColor);
|
||||
for (let i = 0, n = bones.length; i < n; i++) {
|
||||
let bone = bones[i];
|
||||
if (ignoredBones && ignoredBones.indexOf(bone.data.name) > -1) continue;
|
||||
if (!bone.parent) continue;
|
||||
let x = skeletonX + bone.data.length * bone.a + bone.worldX;
|
||||
let y = skeletonY + bone.data.length * bone.c + bone.worldY;
|
||||
shapes.rectLine(true, skeletonX + bone.worldX, skeletonY + bone.worldY, x, y, this.boneWidth * this.scale);
|
||||
}
|
||||
if (this.drawSkeletonXY) shapes.x(skeletonX, skeletonY, 4 * this.scale);
|
||||
}
|
||||
|
||||
if (this.drawRegionAttachments) {
|
||||
shapes.setColor(this.attachmentLineColor);
|
||||
let slots = skeleton.slots;
|
||||
for (let i = 0, n = slots.length; i < n; i++) {
|
||||
let slot = slots[i];
|
||||
let attachment = slot.getAttachment();
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
let regionAttachment = <RegionAttachment>attachment;
|
||||
let vertices = this.vertices;
|
||||
regionAttachment.computeWorldVertices(slot.bone, vertices, 0, 2);
|
||||
shapes.line(vertices[0], vertices[1], vertices[2], vertices[3]);
|
||||
shapes.line(vertices[2], vertices[3], vertices[4], vertices[5]);
|
||||
shapes.line(vertices[4], vertices[5], vertices[6], vertices[7]);
|
||||
shapes.line(vertices[6], vertices[7], vertices[0], vertices[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawMeshHull || this.drawMeshTriangles) {
|
||||
let slots = skeleton.slots;
|
||||
for (let i = 0, n = slots.length; i < n; i++) {
|
||||
let slot = slots[i];
|
||||
if (!slot.bone.active) continue;
|
||||
let attachment = slot.getAttachment();
|
||||
if (!(attachment instanceof MeshAttachment)) continue;
|
||||
let mesh = <MeshAttachment>attachment;
|
||||
if (this.drawRegionAttachments) {
|
||||
shapes.setColor(this.attachmentLineColor);
|
||||
let slots = skeleton.slots;
|
||||
for (let i = 0, n = slots.length; i < n; i++) {
|
||||
let slot = slots[i];
|
||||
let attachment = slot.getAttachment();
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
let regionAttachment = <RegionAttachment>attachment;
|
||||
let vertices = this.vertices;
|
||||
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, 2);
|
||||
let triangles = mesh.triangles;
|
||||
let hullLength = mesh.hullLength;
|
||||
if (this.drawMeshTriangles) {
|
||||
shapes.setColor(this.triangleLineColor);
|
||||
for (let ii = 0, nn = triangles.length; ii < nn; ii += 3) {
|
||||
let v1 = triangles[ii] * 2, v2 = triangles[ii + 1] * 2, v3 = triangles[ii + 2] * 2;
|
||||
shapes.triangle(false, vertices[v1], vertices[v1 + 1], //
|
||||
vertices[v2], vertices[v2 + 1], //
|
||||
vertices[v3], vertices[v3 + 1] //
|
||||
);
|
||||
}
|
||||
}
|
||||
if (this.drawMeshHull && hullLength > 0) {
|
||||
shapes.setColor(this.attachmentLineColor);
|
||||
hullLength = (hullLength >> 1) * 2;
|
||||
let lastX = vertices[hullLength - 2], lastY = vertices[hullLength - 1];
|
||||
for (let ii = 0, nn = hullLength; ii < nn; ii += 2) {
|
||||
let x = vertices[ii], y = vertices[ii + 1];
|
||||
shapes.line(x, y, lastX, lastY);
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
}
|
||||
}
|
||||
regionAttachment.computeWorldVertices(slot.bone, vertices, 0, 2);
|
||||
shapes.line(vertices[0], vertices[1], vertices[2], vertices[3]);
|
||||
shapes.line(vertices[2], vertices[3], vertices[4], vertices[5]);
|
||||
shapes.line(vertices[4], vertices[5], vertices[6], vertices[7]);
|
||||
shapes.line(vertices[6], vertices[7], vertices[0], vertices[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawBoundingBoxes) {
|
||||
let bounds = this.bounds;
|
||||
bounds.update(skeleton, true);
|
||||
shapes.setColor(this.aabbColor);
|
||||
shapes.rect(false, bounds.minX, bounds.minY, bounds.getWidth(), bounds.getHeight());
|
||||
let polygons = bounds.polygons;
|
||||
let boxes = bounds.boundingBoxes;
|
||||
for (let i = 0, n = polygons.length; i < n; i++) {
|
||||
let polygon = polygons[i];
|
||||
shapes.setColor(boxes[i].color);
|
||||
shapes.polygon(polygon, 0, polygon.length);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawPaths) {
|
||||
let slots = skeleton.slots;
|
||||
for (let i = 0, n = slots.length; i < n; i++) {
|
||||
let slot = slots[i];
|
||||
if (!slot.bone.active) continue;
|
||||
let attachment = slot.getAttachment();
|
||||
if (!(attachment instanceof PathAttachment)) continue;
|
||||
let path = <PathAttachment>attachment;
|
||||
let nn = path.worldVerticesLength;
|
||||
let world = this.temp = Utils.setArraySize(this.temp, nn, 0);
|
||||
path.computeWorldVertices(slot, 0, nn, world, 0, 2);
|
||||
let color = this.pathColor;
|
||||
let x1 = world[2], y1 = world[3], x2 = 0, y2 = 0;
|
||||
if (path.closed) {
|
||||
shapes.setColor(color);
|
||||
let cx1 = world[0], cy1 = world[1], cx2 = world[nn - 2], cy2 = world[nn - 1];
|
||||
x2 = world[nn - 4];
|
||||
y2 = world[nn - 3];
|
||||
shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32);
|
||||
shapes.setColor(SkeletonDebugRenderer.LIGHT_GRAY);
|
||||
shapes.line(x1, y1, cx1, cy1);
|
||||
shapes.line(x2, y2, cx2, cy2);
|
||||
}
|
||||
nn -= 4;
|
||||
for (let ii = 4; ii < nn; ii += 6) {
|
||||
let cx1 = world[ii], cy1 = world[ii + 1], cx2 = world[ii + 2], cy2 = world[ii + 3];
|
||||
x2 = world[ii + 4];
|
||||
y2 = world[ii + 5];
|
||||
shapes.setColor(color);
|
||||
shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32);
|
||||
shapes.setColor(SkeletonDebugRenderer.LIGHT_GRAY);
|
||||
shapes.line(x1, y1, cx1, cy1);
|
||||
shapes.line(x2, y2, cx2, cy2);
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
if (this.drawMeshHull || this.drawMeshTriangles) {
|
||||
let slots = skeleton.slots;
|
||||
for (let i = 0, n = slots.length; i < n; i++) {
|
||||
let slot = slots[i];
|
||||
if (!slot.bone.active) continue;
|
||||
let attachment = slot.getAttachment();
|
||||
if (!(attachment instanceof MeshAttachment)) continue;
|
||||
let mesh = <MeshAttachment>attachment;
|
||||
let vertices = this.vertices;
|
||||
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, 2);
|
||||
let triangles = mesh.triangles;
|
||||
let hullLength = mesh.hullLength;
|
||||
if (this.drawMeshTriangles) {
|
||||
shapes.setColor(this.triangleLineColor);
|
||||
for (let ii = 0, nn = triangles.length; ii < nn; ii += 3) {
|
||||
let v1 = triangles[ii] * 2, v2 = triangles[ii + 1] * 2, v3 = triangles[ii + 2] * 2;
|
||||
shapes.triangle(false, vertices[v1], vertices[v1 + 1], //
|
||||
vertices[v2], vertices[v2 + 1], //
|
||||
vertices[v3], vertices[v3 + 1] //
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawBones) {
|
||||
shapes.setColor(this.boneOriginColor);
|
||||
for (let i = 0, n = bones.length; i < n; i++) {
|
||||
let bone = bones[i];
|
||||
if (ignoredBones && ignoredBones.indexOf(bone.data.name) > -1) continue;
|
||||
shapes.circle(true, skeletonX + bone.worldX, skeletonY + bone.worldY, 3 * this.scale, SkeletonDebugRenderer.GREEN, 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawClipping) {
|
||||
let slots = skeleton.slots;
|
||||
shapes.setColor(this.clipColor)
|
||||
for (let i = 0, n = slots.length; i < n; i++) {
|
||||
let slot = slots[i];
|
||||
if (!slot.bone.active) continue;
|
||||
let attachment = slot.getAttachment();
|
||||
if (!(attachment instanceof ClippingAttachment)) continue;
|
||||
let clip = <ClippingAttachment>attachment;
|
||||
let nn = clip.worldVerticesLength;
|
||||
let world = this.temp = Utils.setArraySize(this.temp, nn, 0);
|
||||
clip.computeWorldVertices(slot, 0, nn, world, 0, 2);
|
||||
for (let i = 0, n = world.length; i < n; i += 2) {
|
||||
let x = world[i];
|
||||
let y = world[i + 1];
|
||||
let x2 = world[(i + 2) % world.length];
|
||||
let y2 = world[(i + 3) % world.length];
|
||||
shapes.line(x, y, x2, y2);
|
||||
if (this.drawMeshHull && hullLength > 0) {
|
||||
shapes.setColor(this.attachmentLineColor);
|
||||
hullLength = (hullLength >> 1) * 2;
|
||||
let lastX = vertices[hullLength - 2], lastY = vertices[hullLength - 1];
|
||||
for (let ii = 0, nn = hullLength; ii < nn; ii += 2) {
|
||||
let x = vertices[ii], y = vertices[ii + 1];
|
||||
shapes.line(x, y, lastX, lastY);
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispose () {
|
||||
if (this.drawBoundingBoxes) {
|
||||
let bounds = this.bounds;
|
||||
bounds.update(skeleton, true);
|
||||
shapes.setColor(this.aabbColor);
|
||||
shapes.rect(false, bounds.minX, bounds.minY, bounds.getWidth(), bounds.getHeight());
|
||||
let polygons = bounds.polygons;
|
||||
let boxes = bounds.boundingBoxes;
|
||||
for (let i = 0, n = polygons.length; i < n; i++) {
|
||||
let polygon = polygons[i];
|
||||
shapes.setColor(boxes[i].color);
|
||||
shapes.polygon(polygon, 0, polygon.length);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawPaths) {
|
||||
let slots = skeleton.slots;
|
||||
for (let i = 0, n = slots.length; i < n; i++) {
|
||||
let slot = slots[i];
|
||||
if (!slot.bone.active) continue;
|
||||
let attachment = slot.getAttachment();
|
||||
if (!(attachment instanceof PathAttachment)) continue;
|
||||
let path = <PathAttachment>attachment;
|
||||
let nn = path.worldVerticesLength;
|
||||
let world = this.temp = Utils.setArraySize(this.temp, nn, 0);
|
||||
path.computeWorldVertices(slot, 0, nn, world, 0, 2);
|
||||
let color = this.pathColor;
|
||||
let x1 = world[2], y1 = world[3], x2 = 0, y2 = 0;
|
||||
if (path.closed) {
|
||||
shapes.setColor(color);
|
||||
let cx1 = world[0], cy1 = world[1], cx2 = world[nn - 2], cy2 = world[nn - 1];
|
||||
x2 = world[nn - 4];
|
||||
y2 = world[nn - 3];
|
||||
shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32);
|
||||
shapes.setColor(SkeletonDebugRenderer.LIGHT_GRAY);
|
||||
shapes.line(x1, y1, cx1, cy1);
|
||||
shapes.line(x2, y2, cx2, cy2);
|
||||
}
|
||||
nn -= 4;
|
||||
for (let ii = 4; ii < nn; ii += 6) {
|
||||
let cx1 = world[ii], cy1 = world[ii + 1], cx2 = world[ii + 2], cy2 = world[ii + 3];
|
||||
x2 = world[ii + 4];
|
||||
y2 = world[ii + 5];
|
||||
shapes.setColor(color);
|
||||
shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32);
|
||||
shapes.setColor(SkeletonDebugRenderer.LIGHT_GRAY);
|
||||
shapes.line(x1, y1, cx1, cy1);
|
||||
shapes.line(x2, y2, cx2, cy2);
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawBones) {
|
||||
shapes.setColor(this.boneOriginColor);
|
||||
for (let i = 0, n = bones.length; i < n; i++) {
|
||||
let bone = bones[i];
|
||||
if (ignoredBones && ignoredBones.indexOf(bone.data.name) > -1) continue;
|
||||
shapes.circle(true, skeletonX + bone.worldX, skeletonY + bone.worldY, 3 * this.scale, SkeletonDebugRenderer.GREEN, 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawClipping) {
|
||||
let slots = skeleton.slots;
|
||||
shapes.setColor(this.clipColor)
|
||||
for (let i = 0, n = slots.length; i < n; i++) {
|
||||
let slot = slots[i];
|
||||
if (!slot.bone.active) continue;
|
||||
let attachment = slot.getAttachment();
|
||||
if (!(attachment instanceof ClippingAttachment)) continue;
|
||||
let clip = <ClippingAttachment>attachment;
|
||||
let nn = clip.worldVerticesLength;
|
||||
let world = this.temp = Utils.setArraySize(this.temp, nn, 0);
|
||||
clip.computeWorldVertices(slot, 0, nn, world, 0, 2);
|
||||
for (let i = 0, n = world.length; i < n; i += 2) {
|
||||
let x = world[i];
|
||||
let y = world[i + 1];
|
||||
let x2 = world[(i + 2) % world.length];
|
||||
let y2 = world[(i + 3) % world.length];
|
||||
shapes.line(x, y, x2, y2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispose() {
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,273 +27,277 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
class Renderable {
|
||||
constructor (public vertices: ArrayLike<number>, public numVertices: number, public numFloats: number) { }
|
||||
};
|
||||
import { NumberArrayLike, VertexEffect, Color, SkeletonClipping, Vector2, Utils, Skeleton, BlendMode, RegionAttachment, TextureAtlasRegion, MeshAttachment, ClippingAttachment } from "spine-core";
|
||||
import { GLTexture } from "./GLTexture";
|
||||
import { PolygonBatcher } from "./PolygonBatcher";
|
||||
import { ManagedWebGLRenderingContext, WebGLBlendModeConverter } from "./WebGL";
|
||||
|
||||
export class SkeletonRenderer {
|
||||
static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
||||
|
||||
premultipliedAlpha = false;
|
||||
vertexEffect: VertexEffect = null;
|
||||
private tempColor = new Color();
|
||||
private tempColor2 = new Color();
|
||||
private vertices: ArrayLike<number>;
|
||||
private vertexSize = 2 + 2 + 4;
|
||||
private twoColorTint = false;
|
||||
private renderable: Renderable = new Renderable(null, 0, 0);
|
||||
private clipper: SkeletonClipping = new SkeletonClipping();
|
||||
private temp = new Vector2();
|
||||
private temp2 = new Vector2();
|
||||
private temp3 = new Color();
|
||||
private temp4 = new Color();
|
||||
class Renderable {
|
||||
constructor(public vertices: NumberArrayLike, public numVertices: number, public numFloats: number) { }
|
||||
};
|
||||
|
||||
constructor (context: ManagedWebGLRenderingContext, twoColorTint: boolean = true) {
|
||||
this.twoColorTint = twoColorTint;
|
||||
if (twoColorTint)
|
||||
this.vertexSize += 4;
|
||||
this.vertices = Utils.newFloatArray(this.vertexSize * 1024);
|
||||
}
|
||||
export class SkeletonRenderer {
|
||||
static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
||||
|
||||
draw (batcher: PolygonBatcher, skeleton: Skeleton, slotRangeStart: number = -1, slotRangeEnd: number = -1) {
|
||||
let clipper = this.clipper;
|
||||
let premultipliedAlpha = this.premultipliedAlpha;
|
||||
let twoColorTint = this.twoColorTint;
|
||||
let blendMode: BlendMode = null;
|
||||
premultipliedAlpha = false;
|
||||
vertexEffect: VertexEffect = null;
|
||||
private tempColor = new Color();
|
||||
private tempColor2 = new Color();
|
||||
private vertices: NumberArrayLike;
|
||||
private vertexSize = 2 + 2 + 4;
|
||||
private twoColorTint = false;
|
||||
private renderable: Renderable = new Renderable(null, 0, 0);
|
||||
private clipper: SkeletonClipping = new SkeletonClipping();
|
||||
private temp = new Vector2();
|
||||
private temp2 = new Vector2();
|
||||
private temp3 = new Color();
|
||||
private temp4 = new Color();
|
||||
|
||||
let tempPos = this.temp;
|
||||
let tempUv = this.temp2;
|
||||
let tempLight = this.temp3;
|
||||
let tempDark = this.temp4;
|
||||
constructor(context: ManagedWebGLRenderingContext, twoColorTint: boolean = true) {
|
||||
this.twoColorTint = twoColorTint;
|
||||
if (twoColorTint)
|
||||
this.vertexSize += 4;
|
||||
this.vertices = Utils.newFloatArray(this.vertexSize * 1024);
|
||||
}
|
||||
|
||||
let renderable: Renderable = this.renderable;
|
||||
let uvs: ArrayLike<number> = null;
|
||||
let triangles: Array<number> = null;
|
||||
let drawOrder = skeleton.drawOrder;
|
||||
let attachmentColor: Color = null;
|
||||
let skeletonColor = skeleton.color;
|
||||
let vertexSize = twoColorTint ? 12 : 8;
|
||||
let inRange = false;
|
||||
if (slotRangeStart == -1) inRange = true;
|
||||
for (let i = 0, n = drawOrder.length; i < n; i++) {
|
||||
let clippedVertexSize = clipper.isClipping() ? 2 : vertexSize;
|
||||
let slot = drawOrder[i];
|
||||
if (!slot.bone.active) {
|
||||
clipper.clipEndWithSlot(slot);
|
||||
continue;
|
||||
}
|
||||
draw(batcher: PolygonBatcher, skeleton: Skeleton, slotRangeStart: number = -1, slotRangeEnd: number = -1) {
|
||||
let clipper = this.clipper;
|
||||
let premultipliedAlpha = this.premultipliedAlpha;
|
||||
let twoColorTint = this.twoColorTint;
|
||||
let blendMode: BlendMode = null;
|
||||
|
||||
if (slotRangeStart >= 0 && slotRangeStart == slot.data.index) {
|
||||
inRange = true;
|
||||
}
|
||||
|
||||
if (!inRange) {
|
||||
clipper.clipEndWithSlot(slot);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slotRangeEnd >= 0 && slotRangeEnd == slot.data.index) {
|
||||
inRange = false;
|
||||
}
|
||||
|
||||
let attachment = slot.getAttachment();
|
||||
let texture: GLTexture = null;
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
let region = <RegionAttachment>attachment;
|
||||
renderable.vertices = this.vertices;
|
||||
renderable.numVertices = 4;
|
||||
renderable.numFloats = clippedVertexSize << 2;
|
||||
region.computeWorldVertices(slot.bone, renderable.vertices, 0, clippedVertexSize);
|
||||
triangles = SkeletonRenderer.QUAD_TRIANGLES;
|
||||
uvs = region.uvs;
|
||||
texture = <GLTexture>(<TextureAtlasRegion>region.region.renderObject).page.texture;
|
||||
attachmentColor = region.color;
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
let mesh = <MeshAttachment>attachment;
|
||||
renderable.vertices = this.vertices;
|
||||
renderable.numVertices = (mesh.worldVerticesLength >> 1);
|
||||
renderable.numFloats = renderable.numVertices * clippedVertexSize;
|
||||
if (renderable.numFloats > renderable.vertices.length) {
|
||||
renderable.vertices = this.vertices = spine.Utils.newFloatArray(renderable.numFloats);
|
||||
}
|
||||
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, renderable.vertices, 0, clippedVertexSize);
|
||||
triangles = mesh.triangles;
|
||||
texture = <GLTexture>(<TextureAtlasRegion>mesh.region.renderObject).page.texture;
|
||||
uvs = mesh.uvs;
|
||||
attachmentColor = mesh.color;
|
||||
} else if (attachment instanceof ClippingAttachment) {
|
||||
let clip = <ClippingAttachment>(attachment);
|
||||
clipper.clipStart(slot, clip);
|
||||
continue;
|
||||
} else {
|
||||
clipper.clipEndWithSlot(slot);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (texture) {
|
||||
let slotColor = slot.color;
|
||||
let finalColor = this.tempColor;
|
||||
finalColor.r = skeletonColor.r * slotColor.r * attachmentColor.r;
|
||||
finalColor.g = skeletonColor.g * slotColor.g * attachmentColor.g;
|
||||
finalColor.b = skeletonColor.b * slotColor.b * attachmentColor.b;
|
||||
finalColor.a = skeletonColor.a * slotColor.a * attachmentColor.a;
|
||||
if (premultipliedAlpha) {
|
||||
finalColor.r *= finalColor.a;
|
||||
finalColor.g *= finalColor.a;
|
||||
finalColor.b *= finalColor.a;
|
||||
}
|
||||
let darkColor = this.tempColor2;
|
||||
if (!slot.darkColor)
|
||||
darkColor.set(0, 0, 0, 1.0);
|
||||
else {
|
||||
if (premultipliedAlpha) {
|
||||
darkColor.r = slot.darkColor.r * finalColor.a;
|
||||
darkColor.g = slot.darkColor.g * finalColor.a;
|
||||
darkColor.b = slot.darkColor.b * finalColor.a;
|
||||
} else {
|
||||
darkColor.setFromColor(slot.darkColor);
|
||||
}
|
||||
darkColor.a = premultipliedAlpha ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
let slotBlendMode = slot.data.blendMode;
|
||||
if (slotBlendMode != blendMode) {
|
||||
blendMode = slotBlendMode;
|
||||
batcher.setBlendMode(
|
||||
WebGLBlendModeConverter.getSourceColorGLBlendMode(blendMode, premultipliedAlpha),
|
||||
WebGLBlendModeConverter.getSourceAlphaGLBlendMode(blendMode),
|
||||
WebGLBlendModeConverter.getDestGLBlendMode(blendMode));
|
||||
}
|
||||
|
||||
if (clipper.isClipping()) {
|
||||
clipper.clipTriangles(renderable.vertices, renderable.numFloats, triangles, triangles.length, uvs, finalColor, darkColor, twoColorTint);
|
||||
let clippedVertices = new Float32Array(clipper.clippedVertices);
|
||||
let clippedTriangles = clipper.clippedTriangles;
|
||||
if (this.vertexEffect) {
|
||||
let vertexEffect = this.vertexEffect;
|
||||
let verts = clippedVertices;
|
||||
if (!twoColorTint) {
|
||||
for (let v = 0, n = clippedVertices.length; v < n; v += vertexSize) {
|
||||
tempPos.x = verts[v];
|
||||
tempPos.y = verts[v + 1];
|
||||
tempLight.set(verts[v + 2], verts[v + 3], verts[v + 4], verts[v + 5]);
|
||||
tempUv.x = verts[v + 6];
|
||||
tempUv.y = verts[v + 7];
|
||||
tempDark.set(0, 0, 0, 0);
|
||||
vertexEffect.transform(tempPos, tempUv, tempLight, tempDark);
|
||||
verts[v] = tempPos.x;
|
||||
verts[v + 1] = tempPos.y;
|
||||
verts[v + 2] = tempLight.r;
|
||||
verts[v + 3] = tempLight.g;
|
||||
verts[v + 4] = tempLight.b;
|
||||
verts[v + 5] = tempLight.a;
|
||||
verts[v + 6] = tempUv.x;
|
||||
verts[v + 7] = tempUv.y
|
||||
}
|
||||
} else {
|
||||
for (let v = 0, n = clippedVertices.length; v < n; v += vertexSize) {
|
||||
tempPos.x = verts[v];
|
||||
tempPos.y = verts[v + 1];
|
||||
tempLight.set(verts[v + 2], verts[v + 3], verts[v + 4], verts[v + 5]);
|
||||
tempUv.x = verts[v + 6];
|
||||
tempUv.y = verts[v + 7];
|
||||
tempDark.set(verts[v + 8], verts[v + 9], verts[v + 10], verts[v + 11]);
|
||||
vertexEffect.transform(tempPos, tempUv, tempLight, tempDark);
|
||||
verts[v] = tempPos.x;
|
||||
verts[v + 1] = tempPos.y;
|
||||
verts[v + 2] = tempLight.r;
|
||||
verts[v + 3] = tempLight.g;
|
||||
verts[v + 4] = tempLight.b;
|
||||
verts[v + 5] = tempLight.a;
|
||||
verts[v + 6] = tempUv.x;
|
||||
verts[v + 7] = tempUv.y
|
||||
verts[v + 8] = tempDark.r;
|
||||
verts[v + 9] = tempDark.g;
|
||||
verts[v + 10] = tempDark.b;
|
||||
verts[v + 11] = tempDark.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
batcher.draw(texture, clippedVertices, clippedTriangles);
|
||||
} else {
|
||||
let verts = renderable.vertices;
|
||||
if (this.vertexEffect) {
|
||||
let vertexEffect = this.vertexEffect;
|
||||
if (!twoColorTint) {
|
||||
for (let v = 0, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
|
||||
tempPos.x = verts[v];
|
||||
tempPos.y = verts[v + 1];
|
||||
tempUv.x = uvs[u];
|
||||
tempUv.y = uvs[u + 1]
|
||||
tempLight.setFromColor(finalColor);
|
||||
tempDark.set(0, 0, 0, 0);
|
||||
vertexEffect.transform(tempPos, tempUv, tempLight, tempDark);
|
||||
verts[v] = tempPos.x;
|
||||
verts[v + 1] = tempPos.y;
|
||||
verts[v + 2] = tempLight.r;
|
||||
verts[v + 3] = tempLight.g;
|
||||
verts[v + 4] = tempLight.b;
|
||||
verts[v + 5] = tempLight.a;
|
||||
verts[v + 6] = tempUv.x;
|
||||
verts[v + 7] = tempUv.y
|
||||
}
|
||||
} else {
|
||||
for (let v = 0, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
|
||||
tempPos.x = verts[v];
|
||||
tempPos.y = verts[v + 1];
|
||||
tempUv.x = uvs[u];
|
||||
tempUv.y = uvs[u + 1]
|
||||
tempLight.setFromColor(finalColor);
|
||||
tempDark.setFromColor(darkColor);
|
||||
vertexEffect.transform(tempPos, tempUv, tempLight, tempDark);
|
||||
verts[v] = tempPos.x;
|
||||
verts[v + 1] = tempPos.y;
|
||||
verts[v + 2] = tempLight.r;
|
||||
verts[v + 3] = tempLight.g;
|
||||
verts[v + 4] = tempLight.b;
|
||||
verts[v + 5] = tempLight.a;
|
||||
verts[v + 6] = tempUv.x;
|
||||
verts[v + 7] = tempUv.y
|
||||
verts[v + 8] = tempDark.r;
|
||||
verts[v + 9] = tempDark.g;
|
||||
verts[v + 10] = tempDark.b;
|
||||
verts[v + 11] = tempDark.a;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!twoColorTint) {
|
||||
for (let v = 2, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
|
||||
verts[v] = finalColor.r;
|
||||
verts[v + 1] = finalColor.g;
|
||||
verts[v + 2] = finalColor.b;
|
||||
verts[v + 3] = finalColor.a;
|
||||
verts[v + 4] = uvs[u];
|
||||
verts[v + 5] = uvs[u + 1];
|
||||
}
|
||||
} else {
|
||||
for (let v = 2, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
|
||||
verts[v] = finalColor.r;
|
||||
verts[v + 1] = finalColor.g;
|
||||
verts[v + 2] = finalColor.b;
|
||||
verts[v + 3] = finalColor.a;
|
||||
verts[v + 4] = uvs[u];
|
||||
verts[v + 5] = uvs[u + 1];
|
||||
verts[v + 6] = darkColor.r;
|
||||
verts[v + 7] = darkColor.g;
|
||||
verts[v + 8] = darkColor.b;
|
||||
verts[v + 9] = darkColor.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
let view = (renderable.vertices as Float32Array).subarray(0, renderable.numFloats);
|
||||
batcher.draw(texture, view, triangles);
|
||||
}
|
||||
}
|
||||
let tempPos = this.temp;
|
||||
let tempUv = this.temp2;
|
||||
let tempLight = this.temp3;
|
||||
let tempDark = this.temp4;
|
||||
|
||||
let renderable: Renderable = this.renderable;
|
||||
let uvs: NumberArrayLike = null;
|
||||
let triangles: Array<number> = null;
|
||||
let drawOrder = skeleton.drawOrder;
|
||||
let attachmentColor: Color = null;
|
||||
let skeletonColor = skeleton.color;
|
||||
let vertexSize = twoColorTint ? 12 : 8;
|
||||
let inRange = false;
|
||||
if (slotRangeStart == -1) inRange = true;
|
||||
for (let i = 0, n = drawOrder.length; i < n; i++) {
|
||||
let clippedVertexSize = clipper.isClipping() ? 2 : vertexSize;
|
||||
let slot = drawOrder[i];
|
||||
if (!slot.bone.active) {
|
||||
clipper.clipEndWithSlot(slot);
|
||||
continue;
|
||||
}
|
||||
clipper.clipEnd();
|
||||
|
||||
if (slotRangeStart >= 0 && slotRangeStart == slot.data.index) {
|
||||
inRange = true;
|
||||
}
|
||||
|
||||
if (!inRange) {
|
||||
clipper.clipEndWithSlot(slot);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slotRangeEnd >= 0 && slotRangeEnd == slot.data.index) {
|
||||
inRange = false;
|
||||
}
|
||||
|
||||
let attachment = slot.getAttachment();
|
||||
let texture: GLTexture = null;
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
let region = <RegionAttachment>attachment;
|
||||
renderable.vertices = this.vertices;
|
||||
renderable.numVertices = 4;
|
||||
renderable.numFloats = clippedVertexSize << 2;
|
||||
region.computeWorldVertices(slot.bone, renderable.vertices, 0, clippedVertexSize);
|
||||
triangles = SkeletonRenderer.QUAD_TRIANGLES;
|
||||
uvs = region.uvs;
|
||||
texture = <GLTexture>(<TextureAtlasRegion>region.region.renderObject).page.texture;
|
||||
attachmentColor = region.color;
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
let mesh = <MeshAttachment>attachment;
|
||||
renderable.vertices = this.vertices;
|
||||
renderable.numVertices = (mesh.worldVerticesLength >> 1);
|
||||
renderable.numFloats = renderable.numVertices * clippedVertexSize;
|
||||
if (renderable.numFloats > renderable.vertices.length) {
|
||||
renderable.vertices = this.vertices = spine.Utils.newFloatArray(renderable.numFloats);
|
||||
}
|
||||
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, renderable.vertices, 0, clippedVertexSize);
|
||||
triangles = mesh.triangles;
|
||||
texture = <GLTexture>(<TextureAtlasRegion>mesh.region.renderObject).page.texture;
|
||||
uvs = mesh.uvs;
|
||||
attachmentColor = mesh.color;
|
||||
} else if (attachment instanceof ClippingAttachment) {
|
||||
let clip = <ClippingAttachment>(attachment);
|
||||
clipper.clipStart(slot, clip);
|
||||
continue;
|
||||
} else {
|
||||
clipper.clipEndWithSlot(slot);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (texture) {
|
||||
let slotColor = slot.color;
|
||||
let finalColor = this.tempColor;
|
||||
finalColor.r = skeletonColor.r * slotColor.r * attachmentColor.r;
|
||||
finalColor.g = skeletonColor.g * slotColor.g * attachmentColor.g;
|
||||
finalColor.b = skeletonColor.b * slotColor.b * attachmentColor.b;
|
||||
finalColor.a = skeletonColor.a * slotColor.a * attachmentColor.a;
|
||||
if (premultipliedAlpha) {
|
||||
finalColor.r *= finalColor.a;
|
||||
finalColor.g *= finalColor.a;
|
||||
finalColor.b *= finalColor.a;
|
||||
}
|
||||
let darkColor = this.tempColor2;
|
||||
if (!slot.darkColor)
|
||||
darkColor.set(0, 0, 0, 1.0);
|
||||
else {
|
||||
if (premultipliedAlpha) {
|
||||
darkColor.r = slot.darkColor.r * finalColor.a;
|
||||
darkColor.g = slot.darkColor.g * finalColor.a;
|
||||
darkColor.b = slot.darkColor.b * finalColor.a;
|
||||
} else {
|
||||
darkColor.setFromColor(slot.darkColor);
|
||||
}
|
||||
darkColor.a = premultipliedAlpha ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
let slotBlendMode = slot.data.blendMode;
|
||||
if (slotBlendMode != blendMode) {
|
||||
blendMode = slotBlendMode;
|
||||
batcher.setBlendMode(
|
||||
WebGLBlendModeConverter.getSourceColorGLBlendMode(blendMode, premultipliedAlpha),
|
||||
WebGLBlendModeConverter.getSourceAlphaGLBlendMode(blendMode),
|
||||
WebGLBlendModeConverter.getDestGLBlendMode(blendMode));
|
||||
}
|
||||
|
||||
if (clipper.isClipping()) {
|
||||
clipper.clipTriangles(renderable.vertices, renderable.numFloats, triangles, triangles.length, uvs, finalColor, darkColor, twoColorTint);
|
||||
let clippedVertices = new Float32Array(clipper.clippedVertices);
|
||||
let clippedTriangles = clipper.clippedTriangles;
|
||||
if (this.vertexEffect) {
|
||||
let vertexEffect = this.vertexEffect;
|
||||
let verts = clippedVertices;
|
||||
if (!twoColorTint) {
|
||||
for (let v = 0, n = clippedVertices.length; v < n; v += vertexSize) {
|
||||
tempPos.x = verts[v];
|
||||
tempPos.y = verts[v + 1];
|
||||
tempLight.set(verts[v + 2], verts[v + 3], verts[v + 4], verts[v + 5]);
|
||||
tempUv.x = verts[v + 6];
|
||||
tempUv.y = verts[v + 7];
|
||||
tempDark.set(0, 0, 0, 0);
|
||||
vertexEffect.transform(tempPos, tempUv, tempLight, tempDark);
|
||||
verts[v] = tempPos.x;
|
||||
verts[v + 1] = tempPos.y;
|
||||
verts[v + 2] = tempLight.r;
|
||||
verts[v + 3] = tempLight.g;
|
||||
verts[v + 4] = tempLight.b;
|
||||
verts[v + 5] = tempLight.a;
|
||||
verts[v + 6] = tempUv.x;
|
||||
verts[v + 7] = tempUv.y
|
||||
}
|
||||
} else {
|
||||
for (let v = 0, n = clippedVertices.length; v < n; v += vertexSize) {
|
||||
tempPos.x = verts[v];
|
||||
tempPos.y = verts[v + 1];
|
||||
tempLight.set(verts[v + 2], verts[v + 3], verts[v + 4], verts[v + 5]);
|
||||
tempUv.x = verts[v + 6];
|
||||
tempUv.y = verts[v + 7];
|
||||
tempDark.set(verts[v + 8], verts[v + 9], verts[v + 10], verts[v + 11]);
|
||||
vertexEffect.transform(tempPos, tempUv, tempLight, tempDark);
|
||||
verts[v] = tempPos.x;
|
||||
verts[v + 1] = tempPos.y;
|
||||
verts[v + 2] = tempLight.r;
|
||||
verts[v + 3] = tempLight.g;
|
||||
verts[v + 4] = tempLight.b;
|
||||
verts[v + 5] = tempLight.a;
|
||||
verts[v + 6] = tempUv.x;
|
||||
verts[v + 7] = tempUv.y
|
||||
verts[v + 8] = tempDark.r;
|
||||
verts[v + 9] = tempDark.g;
|
||||
verts[v + 10] = tempDark.b;
|
||||
verts[v + 11] = tempDark.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
batcher.draw(texture, clippedVertices, clippedTriangles);
|
||||
} else {
|
||||
let verts = renderable.vertices;
|
||||
if (this.vertexEffect) {
|
||||
let vertexEffect = this.vertexEffect;
|
||||
if (!twoColorTint) {
|
||||
for (let v = 0, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
|
||||
tempPos.x = verts[v];
|
||||
tempPos.y = verts[v + 1];
|
||||
tempUv.x = uvs[u];
|
||||
tempUv.y = uvs[u + 1]
|
||||
tempLight.setFromColor(finalColor);
|
||||
tempDark.set(0, 0, 0, 0);
|
||||
vertexEffect.transform(tempPos, tempUv, tempLight, tempDark);
|
||||
verts[v] = tempPos.x;
|
||||
verts[v + 1] = tempPos.y;
|
||||
verts[v + 2] = tempLight.r;
|
||||
verts[v + 3] = tempLight.g;
|
||||
verts[v + 4] = tempLight.b;
|
||||
verts[v + 5] = tempLight.a;
|
||||
verts[v + 6] = tempUv.x;
|
||||
verts[v + 7] = tempUv.y
|
||||
}
|
||||
} else {
|
||||
for (let v = 0, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
|
||||
tempPos.x = verts[v];
|
||||
tempPos.y = verts[v + 1];
|
||||
tempUv.x = uvs[u];
|
||||
tempUv.y = uvs[u + 1]
|
||||
tempLight.setFromColor(finalColor);
|
||||
tempDark.setFromColor(darkColor);
|
||||
vertexEffect.transform(tempPos, tempUv, tempLight, tempDark);
|
||||
verts[v] = tempPos.x;
|
||||
verts[v + 1] = tempPos.y;
|
||||
verts[v + 2] = tempLight.r;
|
||||
verts[v + 3] = tempLight.g;
|
||||
verts[v + 4] = tempLight.b;
|
||||
verts[v + 5] = tempLight.a;
|
||||
verts[v + 6] = tempUv.x;
|
||||
verts[v + 7] = tempUv.y
|
||||
verts[v + 8] = tempDark.r;
|
||||
verts[v + 9] = tempDark.g;
|
||||
verts[v + 10] = tempDark.b;
|
||||
verts[v + 11] = tempDark.a;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!twoColorTint) {
|
||||
for (let v = 2, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
|
||||
verts[v] = finalColor.r;
|
||||
verts[v + 1] = finalColor.g;
|
||||
verts[v + 2] = finalColor.b;
|
||||
verts[v + 3] = finalColor.a;
|
||||
verts[v + 4] = uvs[u];
|
||||
verts[v + 5] = uvs[u + 1];
|
||||
}
|
||||
} else {
|
||||
for (let v = 2, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
|
||||
verts[v] = finalColor.r;
|
||||
verts[v + 1] = finalColor.g;
|
||||
verts[v + 2] = finalColor.b;
|
||||
verts[v + 3] = finalColor.a;
|
||||
verts[v + 4] = uvs[u];
|
||||
verts[v + 5] = uvs[u + 1];
|
||||
verts[v + 6] = darkColor.r;
|
||||
verts[v + 7] = darkColor.g;
|
||||
verts[v + 8] = darkColor.b;
|
||||
verts[v + 9] = darkColor.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
let view = (renderable.vertices as Float32Array).subarray(0, renderable.numFloats);
|
||||
batcher.draw(texture, view, triangles);
|
||||
}
|
||||
}
|
||||
|
||||
clipper.clipEndWithSlot(slot);
|
||||
}
|
||||
clipper.clipEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,95 +27,95 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
export class Vector3 {
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
import { Matrix4, M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23, M30, M31, M32, M33 } from "./Matrix4";
|
||||
|
||||
constructor (x: number = 0, y: number = 0, z: number = 0) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
export class Vector3 {
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
|
||||
setFrom (v: Vector3): Vector3 {
|
||||
this.x = v.x;
|
||||
this.y = v.y;
|
||||
this.z = v.z;
|
||||
return this;
|
||||
}
|
||||
constructor(x: number = 0, y: number = 0, z: number = 0) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
set (x: number, y: number, z: number): Vector3 {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
setFrom(v: Vector3): Vector3 {
|
||||
this.x = v.x;
|
||||
this.y = v.y;
|
||||
this.z = v.z;
|
||||
return this;
|
||||
}
|
||||
|
||||
add (v: Vector3): Vector3 {
|
||||
this.x += v.x;
|
||||
this.y += v.y;
|
||||
this.z += v.z;
|
||||
return this;
|
||||
}
|
||||
set(x: number, y: number, z: number): Vector3 {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
sub (v: Vector3): Vector3 {
|
||||
this.x -= v.x;
|
||||
this.y -= v.y;
|
||||
this.z -= v.z;
|
||||
return this;
|
||||
}
|
||||
add(v: Vector3): Vector3 {
|
||||
this.x += v.x;
|
||||
this.y += v.y;
|
||||
this.z += v.z;
|
||||
return this;
|
||||
}
|
||||
|
||||
scale (s: number): Vector3 {
|
||||
this.x *= s;
|
||||
this.y *= s;
|
||||
this.z *= s;
|
||||
return this;
|
||||
}
|
||||
sub(v: Vector3): Vector3 {
|
||||
this.x -= v.x;
|
||||
this.y -= v.y;
|
||||
this.z -= v.z;
|
||||
return this;
|
||||
}
|
||||
|
||||
normalize (): Vector3 {
|
||||
let len = this.length();
|
||||
if (len == 0) return this;
|
||||
len = 1 / len;
|
||||
this.x *= len;
|
||||
this.y *= len;
|
||||
this.z *= len;
|
||||
return this;
|
||||
}
|
||||
scale(s: number): Vector3 {
|
||||
this.x *= s;
|
||||
this.y *= s;
|
||||
this.z *= s;
|
||||
return this;
|
||||
}
|
||||
|
||||
cross (v: Vector3): Vector3 {
|
||||
return this.set(this.y * v.z - this.z * v.y, this.z * v.x - this.x * v.z, this.x * v.y - this.y * v.x)
|
||||
}
|
||||
normalize(): Vector3 {
|
||||
let len = this.length();
|
||||
if (len == 0) return this;
|
||||
len = 1 / len;
|
||||
this.x *= len;
|
||||
this.y *= len;
|
||||
this.z *= len;
|
||||
return this;
|
||||
}
|
||||
|
||||
multiply (matrix: Matrix4): Vector3 {
|
||||
let l_mat = matrix.values;
|
||||
return this.set(this.x * l_mat[M00] + this.y * l_mat[M01] + this.z * l_mat[M02] + l_mat[M03],
|
||||
this.x * l_mat[M10] + this.y * l_mat[M11] + this.z * l_mat[M12] + l_mat[M13],
|
||||
this.x * l_mat[M20] + this.y * l_mat[M21] + this.z * l_mat[M22] + l_mat[M23]);
|
||||
}
|
||||
cross(v: Vector3): Vector3 {
|
||||
return this.set(this.y * v.z - this.z * v.y, this.z * v.x - this.x * v.z, this.x * v.y - this.y * v.x)
|
||||
}
|
||||
|
||||
project (matrix: Matrix4): Vector3 {
|
||||
let l_mat = matrix.values;
|
||||
let l_w = 1 / (this.x * l_mat[M30] + this.y * l_mat[M31] + this.z * l_mat[M32] + l_mat[M33]);
|
||||
return this.set((this.x * l_mat[M00] + this.y * l_mat[M01] + this.z * l_mat[M02] + l_mat[M03]) * l_w,
|
||||
(this.x * l_mat[M10] + this.y * l_mat[M11] + this.z * l_mat[M12] + l_mat[M13]) * l_w,
|
||||
(this.x * l_mat[M20] + this.y * l_mat[M21] + this.z * l_mat[M22] + l_mat[M23]) * l_w);
|
||||
}
|
||||
multiply(matrix: Matrix4): Vector3 {
|
||||
let l_mat = matrix.values;
|
||||
return this.set(this.x * l_mat[M00] + this.y * l_mat[M01] + this.z * l_mat[M02] + l_mat[M03],
|
||||
this.x * l_mat[M10] + this.y * l_mat[M11] + this.z * l_mat[M12] + l_mat[M13],
|
||||
this.x * l_mat[M20] + this.y * l_mat[M21] + this.z * l_mat[M22] + l_mat[M23]);
|
||||
}
|
||||
|
||||
dot (v: Vector3): number {
|
||||
return this.x * v.x + this.y * v.y + this.z * v.z;
|
||||
}
|
||||
project(matrix: Matrix4): Vector3 {
|
||||
let l_mat = matrix.values;
|
||||
let l_w = 1 / (this.x * l_mat[M30] + this.y * l_mat[M31] + this.z * l_mat[M32] + l_mat[M33]);
|
||||
return this.set((this.x * l_mat[M00] + this.y * l_mat[M01] + this.z * l_mat[M02] + l_mat[M03]) * l_w,
|
||||
(this.x * l_mat[M10] + this.y * l_mat[M11] + this.z * l_mat[M12] + l_mat[M13]) * l_w,
|
||||
(this.x * l_mat[M20] + this.y * l_mat[M21] + this.z * l_mat[M22] + l_mat[M23]) * l_w);
|
||||
}
|
||||
|
||||
length (): number {
|
||||
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
||||
}
|
||||
dot(v: Vector3): number {
|
||||
return this.x * v.x + this.y * v.y + this.z * v.z;
|
||||
}
|
||||
|
||||
distance (v: Vector3): number {
|
||||
let a = v.x - this.x;
|
||||
let b = v.y - this.y;
|
||||
let c = v.z - this.z;
|
||||
return Math.sqrt(a * a + b * b + c * c);
|
||||
}
|
||||
length(): number {
|
||||
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
||||
}
|
||||
|
||||
distance(v: Vector3): number {
|
||||
let a = v.x - this.x;
|
||||
let b = v.y - this.y;
|
||||
let c = v.z - this.z;
|
||||
return Math.sqrt(a * a + b * b + c * c);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,81 +27,81 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
module spine.webgl {
|
||||
export class ManagedWebGLRenderingContext {
|
||||
public canvas: HTMLCanvasElement | OffscreenCanvas;
|
||||
public gl: WebGLRenderingContext;
|
||||
private restorables = new Array<Restorable>();
|
||||
import { Restorable, BlendMode } from "spine-core";
|
||||
|
||||
constructor (canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | EventTarget, contextConfig: any = { alpha: "true" }) {
|
||||
if (!((canvasOrContext instanceof WebGLRenderingContext) || (typeof WebGL2RenderingContext !== 'undefined' && canvasOrContext instanceof WebGL2RenderingContext)))
|
||||
this.setupCanvas(canvasOrContext, contextConfig);
|
||||
else {
|
||||
this.gl = canvasOrContext;
|
||||
this.canvas = this.gl.canvas;
|
||||
}
|
||||
}
|
||||
export class ManagedWebGLRenderingContext {
|
||||
public canvas: HTMLCanvasElement | OffscreenCanvas;
|
||||
public gl: WebGLRenderingContext;
|
||||
private restorables = new Array<Restorable>();
|
||||
|
||||
private setupCanvas (canvas: any, contextConfig: any) {
|
||||
this.gl = <WebGLRenderingContext>(canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
|
||||
this.canvas = canvas;
|
||||
canvas.addEventListener("webglcontextlost", (e: any) => {
|
||||
let event = <WebGLContextEvent>e;
|
||||
if (e) e.preventDefault();
|
||||
});
|
||||
|
||||
canvas.addEventListener("webglcontextrestored", (e: any) => {
|
||||
for (let i = 0, n = this.restorables.length; i < n; i++)
|
||||
this.restorables[i].restore();
|
||||
});
|
||||
}
|
||||
|
||||
addRestorable (restorable: Restorable) {
|
||||
this.restorables.push(restorable);
|
||||
}
|
||||
|
||||
removeRestorable (restorable: Restorable) {
|
||||
let index = this.restorables.indexOf(restorable);
|
||||
if (index > -1) this.restorables.splice(index, 1);
|
||||
constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | EventTarget, contextConfig: any = { alpha: "true" }) {
|
||||
if (!((canvasOrContext instanceof WebGLRenderingContext) || (typeof WebGL2RenderingContext !== 'undefined' && canvasOrContext instanceof WebGL2RenderingContext)))
|
||||
this.setupCanvas(canvasOrContext, contextConfig);
|
||||
else {
|
||||
this.gl = canvasOrContext;
|
||||
this.canvas = this.gl.canvas;
|
||||
}
|
||||
}
|
||||
|
||||
const ONE = 1;
|
||||
const ONE_MINUS_SRC_COLOR = 0x0301;
|
||||
const SRC_ALPHA = 0x0302;
|
||||
const ONE_MINUS_SRC_ALPHA = 0x0303;
|
||||
const ONE_MINUS_DST_ALPHA = 0x0305;
|
||||
const DST_COLOR = 0x0306;
|
||||
private setupCanvas(canvas: any, contextConfig: any) {
|
||||
this.gl = <WebGLRenderingContext>(canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
|
||||
this.canvas = canvas;
|
||||
canvas.addEventListener("webglcontextlost", (e: any) => {
|
||||
let event = <WebGLContextEvent>e;
|
||||
if (e) e.preventDefault();
|
||||
});
|
||||
|
||||
export class WebGLBlendModeConverter {
|
||||
static getDestGLBlendMode (blendMode: BlendMode) {
|
||||
switch (blendMode) {
|
||||
case BlendMode.Normal: return ONE_MINUS_SRC_ALPHA;
|
||||
case BlendMode.Additive: return ONE;
|
||||
case BlendMode.Multiply: return ONE_MINUS_SRC_ALPHA;
|
||||
case BlendMode.Screen: return ONE_MINUS_SRC_ALPHA;
|
||||
default: throw new Error("Unknown blend mode: " + blendMode);
|
||||
}
|
||||
canvas.addEventListener("webglcontextrestored", (e: any) => {
|
||||
for (let i = 0, n = this.restorables.length; i < n; i++)
|
||||
this.restorables[i].restore();
|
||||
});
|
||||
}
|
||||
|
||||
addRestorable(restorable: Restorable) {
|
||||
this.restorables.push(restorable);
|
||||
}
|
||||
|
||||
removeRestorable(restorable: Restorable) {
|
||||
let index = this.restorables.indexOf(restorable);
|
||||
if (index > -1) this.restorables.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const ONE = 1;
|
||||
const ONE_MINUS_SRC_COLOR = 0x0301;
|
||||
const SRC_ALPHA = 0x0302;
|
||||
const ONE_MINUS_SRC_ALPHA = 0x0303;
|
||||
const ONE_MINUS_DST_ALPHA = 0x0305;
|
||||
const DST_COLOR = 0x0306;
|
||||
|
||||
export class WebGLBlendModeConverter {
|
||||
static getDestGLBlendMode(blendMode: BlendMode) {
|
||||
switch (blendMode) {
|
||||
case BlendMode.Normal: return ONE_MINUS_SRC_ALPHA;
|
||||
case BlendMode.Additive: return ONE;
|
||||
case BlendMode.Multiply: return ONE_MINUS_SRC_ALPHA;
|
||||
case BlendMode.Screen: return ONE_MINUS_SRC_ALPHA;
|
||||
default: throw new Error("Unknown blend mode: " + blendMode);
|
||||
}
|
||||
}
|
||||
|
||||
static getSourceColorGLBlendMode (blendMode: BlendMode, premultipliedAlpha: boolean = false) {
|
||||
switch (blendMode) {
|
||||
case BlendMode.Normal: return premultipliedAlpha ? ONE : SRC_ALPHA;
|
||||
case BlendMode.Additive: return premultipliedAlpha ? ONE : SRC_ALPHA;
|
||||
case BlendMode.Multiply: return DST_COLOR;
|
||||
case BlendMode.Screen: return ONE;
|
||||
default: throw new Error("Unknown blend mode: " + blendMode);
|
||||
}
|
||||
static getSourceColorGLBlendMode(blendMode: BlendMode, premultipliedAlpha: boolean = false) {
|
||||
switch (blendMode) {
|
||||
case BlendMode.Normal: return premultipliedAlpha ? ONE : SRC_ALPHA;
|
||||
case BlendMode.Additive: return premultipliedAlpha ? ONE : SRC_ALPHA;
|
||||
case BlendMode.Multiply: return DST_COLOR;
|
||||
case BlendMode.Screen: return ONE;
|
||||
default: throw new Error("Unknown blend mode: " + blendMode);
|
||||
}
|
||||
}
|
||||
|
||||
static getSourceAlphaGLBlendMode (blendMode: BlendMode) {
|
||||
switch (blendMode) {
|
||||
case BlendMode.Normal: return ONE;
|
||||
case BlendMode.Additive: return ONE;
|
||||
case BlendMode.Multiply: return ONE_MINUS_SRC_ALPHA;
|
||||
case BlendMode.Screen: return ONE_MINUS_SRC_COLOR;
|
||||
default: throw new Error("Unknown blend mode: " + blendMode);
|
||||
}
|
||||
static getSourceAlphaGLBlendMode(blendMode: BlendMode) {
|
||||
switch (blendMode) {
|
||||
case BlendMode.Normal: return ONE;
|
||||
case BlendMode.Additive: return ONE;
|
||||
case BlendMode.Multiply: return ONE_MINUS_SRC_ALPHA;
|
||||
case BlendMode.Screen: return ONE_MINUS_SRC_COLOR;
|
||||
default: throw new Error("Unknown blend mode: " + blendMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
43
spine-ts/spine-webgl/src/index.ts
Normal file
43
spine-ts/spine-webgl/src/index.ts
Normal file
@ -0,0 +1,43 @@
|
||||
export * from './AssetManager';
|
||||
export * from './Camera';
|
||||
export * from './GLTexture';
|
||||
export * from './Input';
|
||||
export * from './LoadingScreen';
|
||||
export * from './Matrix4';
|
||||
export * from './Mesh';
|
||||
export * from './PolygonBatcher';
|
||||
export * from './SceneRenderer';
|
||||
export * from './Shader';
|
||||
export * from './ShapeRenderer';
|
||||
export * from './SkeletonDebugRenderer';
|
||||
export * from './SkeletonRenderer';
|
||||
export * from './Vector3';
|
||||
export * from './WebGL';
|
||||
|
||||
export * from "spine-core";
|
||||
|
||||
// Before modularization, we would expose spine-core on the global
|
||||
// `spine` object, and spine-webgl on the global `spine.webgl` object.
|
||||
// This was used by clients when including spine-webgl via <script src="spine-webgl.js">
|
||||
//
|
||||
// Now with modularization and using esbuild for bundling, we need to emulate this old
|
||||
// behaviour as to not break old clients.
|
||||
//
|
||||
// We pass `--global-name=spine` to esbuild. This will create an object containing
|
||||
// all exports and assign it to the global variable called `spine`.
|
||||
//
|
||||
// That solves half the issue. We also need to assign the exports object to
|
||||
// `spine.webgl`. esbuild creates a local variable called `scr_exports` pointing
|
||||
// to the exports object. We get to it via eval, then assign it to itself, on a new
|
||||
// property called `webgl`. The client can then access the APIs through `spine` and
|
||||
// `spine.webgl` as before (with the caveat that both spine-core and spine-webgl are
|
||||
// now in `spine` and `spine.webgl`).
|
||||
//
|
||||
// This will break if esbuild renames the variable `src_exports` pointing to
|
||||
// the exports object.
|
||||
declare global {
|
||||
var spine: any;
|
||||
}
|
||||
|
||||
let exports = eval("src_exports");
|
||||
exports.webgl = exports;
|
||||
24
spine-ts/spine-webgl/tsconfig.json
Normal file
24
spine-ts/spine-webgl/tsconfig.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
"paths": {
|
||||
"spine-core": [
|
||||
"../spine-core/src"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"dist/**/*.d.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../spine-core"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,12 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "es2015",
|
||||
"noImplicitAny": true,
|
||||
"preserveConstEnums": true,
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"isolatedModules": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"ES2015"
|
||||
@ -14,8 +12,6 @@
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"composite": true,
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
"moduleResolution": "node",
|
||||
}
|
||||
}
|
||||
@ -7,8 +7,5 @@
|
||||
{
|
||||
"path": "./spine-canvas"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@esotericsoftware/spine-core": "./spine-core/src/index.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user