feat: graphics

This commit is contained in:
cha0s 2019-03-18 20:06:47 -05:00
parent 86b5d7260c
commit f22ea42b54
9 changed files with 348 additions and 1 deletions

View File

@ -0,0 +1,50 @@
import {compose} from '@avocado/core';
import {Property} from '@avocado/mixins';
const decorate = compose(
Property('red'),
Property('green'),
Property('blue'),
Property('alpha'),
)
export class Color {
static fromCss(css) {
if ('#'.charCodeAt(0) === css.charCodeAt(0)) {
let hex = css.substr(1);
if (3 === hex.length) {
hex = hex.split('').map((c) => c + c).join('');
}
const red = parseInt(hex.substr(0, 2), 16);
const green = parseInt(hex.substr(2, 2), 16);
const blue = parseInt(hex.substr(4, 2), 16);
return new Color(red, green, blue);
}
else {
const colors = css.replace(
/\s/g, ''
).match(
/rgba?\((.*)\)/
)[1].split(',');
return new Color(colors[0], colors[1], colors[2], colors[3] || 1);
}
}
constructor(red = 255, green = 0, blue = 255, alpha = 1) {
this.red = red;
this.green = green;
this.blue = blue;
this.alpha = alpha;
}
toCss() {
return `rgba(${this.red}, ${this.green}, ${this.blue}, ${this.alpha})`;
}
toInteger() {
return (this.red << 16) | (this.green << 8) | this.blue;
}
}

View File

@ -0,0 +1,37 @@
const PIXI = 'undefined' !== typeof window ? require('pixi.js') : undefined;
import {Renderable} from './renderable';
export class Container extends Renderable {
constructor() {
super();
this._children = [];
this.internal = PIXI ? new PIXI.Container() : undefined;
}
addChild(child) {
this._children.push(child);
this.internal.addChild(child.internal);
}
children() {
return this._children;
}
removeChild(child) {
const index = this._children.indexOf(child);
if (-1 === index) {
return;
}
this._children.splice(index, 1);
this.internal.removeChild(child.internal);
}
removeAllChildren() {
for (const child of this._children) {
this.removeChild(child);
}
}
}

View File

@ -0,0 +1,56 @@
const PIXI = 'undefined' !== typeof window ? require('pixi.js') : undefined;
import {Resource} from '@avocado/resource';
const baseTextureCache = {};
export class Image extends Resource {
constructor() {
super();
this.texture = null;
}
static load(uri) {
return this.loadBaseTexture(uri).then((baseTexture) => {
const image = new Image();
image.uri = uri;
image.texture = new PIXI.Texture(baseTexture);
return image;
});
}
static loadBaseTexture(uri) {
if (baseTextureCache[uri]) {
return Promise.resolve(baseTextureCache[uri]);
}
return new Promise((resolve, reject) => {
const baseTexture = PIXI.BaseTexture.fromImage(uri);
baseTexture.on('error', () => {
reject(new Error(`Couldn't load image "${uri}"`));
});
baseTexture.on('loaded', () => {
resolve(baseTextureCache[uri] = baseTexture);
});
});
}
get height() {
if (!this.texture) {
return 0;
}
return this.texture.height;
}
get size() {
return [this.width, this.height];
}
get width() {
if (!this.texture) {
return 0;
}
return this.texture.width;
}
}

View File

@ -0,0 +1,7 @@
export {Color} from './color';
export {Container} from './container';
export {Image} from './image';
export {Primitives} from './primitives';
export {Renderable} from './renderable';
export {Renderer} from './renderer';
export {Sprite} from './sprite';

View File

@ -8,7 +8,9 @@
"@avocado/core": "1.x",
"@avocado/math": "1.x",
"@avocado/mixins": "1.x",
"@avocado/resource": "1.x",
"debug": "^3.1.0",
"immutable": "4.0.0-rc.12"
"immutable": "4.0.0-rc.12",
"pixi.js": "4.8.6"
}
}

View File

@ -0,0 +1,67 @@
const PIXI = 'undefined' !== typeof window ? require('pixi.js') : undefined;
import {Color} from './color';
import {Renderable} from './renderable';
export class Primitives extends Renderable {
static fillStyle(color) {
return {color};
}
static lineStyle(color, thickness = 1) {
return {color, thickness};
}
constructor() {
super();
this.internal = new PIXI.Graphics();
}
clear() {
this.internal.clear();
}
drawCircle(position, radius, lineStyle, fillStyle) {
this._wrapStyle('drawCircle', '3rd', lineStyle, fillStyle, () => {
this.internal.drawCircle(position[0], position[1], radius);
});
}
drawLine(p1, p2, lineStyle, fillStyle) {
this._wrapStyle('drawLine', '3rd', lineStyle, fillStyle, () => {
this.internal.moveTo(p1[0], p1[1]);
this.internal.lineTo(p2[0], p2[1]);
});
}
drawRectangle(rectangle, lineStyle, fillStyle) {
this._wrapStyle('drawLine', '2nd', lineStyle, fillStyle, () => {
this.internal.drawRect(
rectangle[0],
rectangle[1],
rectangle[2],
rectangle[3]
);
});
}
_wrapStyle(method, where, lineStyle, fillStyle, fn) {
if (!lineStyle) {
throw new TypeError(
`Primitives::${method} expects lineStyle as ${where} parameter`
);
}
if (fillStyle) {
const {color} = fillStyle;
this.internal.beginFill(color.toInteger(), color.alpha)
}
const {color, thickness} = lineStyle;
this.internal.lineStyle(thickness, color.toInteger(), color.alpha)
fn();
if (fillStyle) {
this.internal.endFill();
}
}
}

View File

@ -0,0 +1,57 @@
export class Renderable {
get alpha() {
return this.internal.alpha;
}
set alpha(alpha) {
this.internal.alpha = alpha;
}
get isValid() {
return !!this.internal;
}
get position() {
return [this.internal.x, this.internal.y];
}
set position(position) {
this.internal.x = position[0];
this.internal.y = position[1];
}
get rotation() {
return this.internal.rotation;
}
set rotation(rotation) {
this.internal.rotation = rotation;
}
get visible() {
return this.internal.visible;
}
set visible(isVisible) {
this.internal.visible = isVisible;
}
get x() {
return this.internal.x;
}
set x(x) {
this.internal.x = x;
}
get y() {
return this.internal.y;
}
set y(y) {
this.internal.y = y;
}
}

View File

@ -0,0 +1,45 @@
const PIXI = 'undefined' !== typeof window ? require('pixi.js') : undefined;
export class Renderer {
constructor(size, type = 'auto') {
switch (type) {
case 'auto':
this.renderer = PIXI.autoDetectRenderer(size[0], size[1]);
break;
case 'canvas':
this.renderer = new PIXI.CanvasRenderer(size[0], size[1]);
break;
case 'auto':
this.renderer = new PIXI.Renderer(size[0], size[1]);
break;
}
}
destroy() {
this.renderer.destroy();
}
get element() {
return this.renderer.view;
}
get height() {
return this.element.height;
}
render(item) {
this.renderer.render(item.internal);
}
get size() {
return [this.width, this.height];
}
get width() {
return this.element.width;
}
}

View File

@ -0,0 +1,26 @@
const PIXI = 'undefined' !== typeof window ? require('pixi.js') : undefined;
import {Renderable} from './renderable';
export class Sprite extends Renderable {
constructor(image) {
super();
this._image = image;
this.internal = new PIXI.Sprite(image.texture);
}
get image() {
return this._image;
}
setSourceRectangle(rectangle) {
this._image.texture.frame = {
x: rectangle[0],
y: rectangle[1],
width: rectangle[2],
height: rectangle[3],
};
}
}