Archive commit

This commit is contained in:
Erik McClure
2019-08-28 21:15:02 -07:00
commit 735845746e
1435 changed files with 140724 additions and 0 deletions
@@ -0,0 +1,4 @@
canvas.pixelart.sprite-box(#canvas [tooltip]="sprite?.title")
.sprite-box-none(*ngIf="!sprite")
fa-icon([icon]="noneIcon" [fixedWidth]="true")
.sprite-box-index(*ngIf="debug" aria-hidden="true") {{index}}
@@ -0,0 +1,30 @@
@import '../../../../styles/partials/variables';
:host {
position: relative;
cursor: pointer;
overflow: hidden;
display: block;
}
.sprite-box-none {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
color: darken($text-muted, 20%);
pointer-events: none;
}
.sprite-box-index {
position: absolute;
left: 3px;
top: 0;
color: darken($text-muted, 20%);
font-size: 8px;
}
@@ -0,0 +1,186 @@
import {
Component, Input, AfterViewInit, ViewChild, ElementRef, NgZone, DoCheck, IterableDiffers, IterableDiffer, OnChanges
} from '@angular/core';
import { Rect, Sprite, ColorExtra, Palette } from '../../../common/interfaces';
import { parseColor, colorToCSS } from '../../../common/color';
import { mockPaletteManager, toColorList, getColorsFromSet } from '../../../common/ponyInfo';
import { ContextSpriteBatch } from '../../../graphics/contextSpriteBatch';
import { createCanvas, disableImageSmoothing, resizeCanvas } from '../../../client/canvasUtils';
import { WHITE } from '../../../common/colors';
import { rect } from '../../../common/rect';
import { loadAndInitSpriteSheets } from '../../../client/spriteUtils';
import { faTimes } from '../../../client/icons';
import { paletteSpriteSheet } from '../../../generated/sprites';
let redrawFrame = 0;
const forRedraw: SpriteBox[] = [];
function drawAll() {
redrawFrame = 0;
forRedraw.forEach(box => box.draw());
forRedraw.length = 0;
}
@Component({
selector: 'sprite-box',
templateUrl: 'sprite-box.pug',
styleUrls: ['sprite-box.scss'],
})
export class SpriteBox implements AfterViewInit, OnChanges, DoCheck {
readonly debug = DEVELOPMENT;
readonly noneIcon = faTimes;
@Input() size = 52;
@Input() scale = 2;
@Input() x = 0;
@Input() y = 0;
@Input() center = true;
@Input() index?: number;
@Input() sprite?: ColorExtra;
@Input() palette?: Palette;
@Input() fill?: string[] | string;
@Input() outline?: string[] | string;
@Input() reverseExtra?: boolean;
@Input() timestamp: any;
@Input() invisible = false;
@Input() darken = true;
@ViewChild('canvas', { static: true }) canvas!: ElementRef;
private _circle?: string;
private fillDiffer: IterableDiffer<string>;
private outlineDiffer: IterableDiffer<string>;
private batch?: ContextSpriteBatch;
constructor(private zone: NgZone, iterableDiffers: IterableDiffers) {
this.fillDiffer = iterableDiffers.find([]).create<string>();
this.outlineDiffer = iterableDiffers.find([]).create<string>();
}
@Input() get circle() {
return this._circle;
}
set circle(value) {
this._circle = colorToCSS(parseColor(value || ''));
}
ngAfterViewInit() {
loadAndInitSpriteSheets().then(() => this.redraw());
}
ngDoCheck() {
const fillChanges = this.fill && Array.isArray(this.fill) && this.fillDiffer.diff(this.fill);
const outlineChanges = this.outline && Array.isArray(this.outline) && this.outlineDiffer.diff(this.outline);
if (fillChanges || outlineChanges) {
this.redraw();
}
}
ngOnChanges() {
this.redraw();
}
private redraw() {
if (!redrawFrame) {
this.zone.runOutsideAngular(() => redrawFrame = requestAnimationFrame(drawAll));
}
if (forRedraw.indexOf(this) === -1) {
forRedraw.push(this);
}
}
draw() {
const size = this.size;
const scale = this.scale;
const canvas = this.canvas.nativeElement as HTMLCanvasElement;
if (!size || this.invisible)
return;
if (canvas.width !== size || canvas.height !== size) {
canvas.width = size;
canvas.height = size;
}
const context = canvas.getContext('2d');
if (!context)
return;
context.save();
context.clearRect(0, 0, canvas.width, canvas.height);
const sprite = this.sprite;
if (sprite) {
if (this.circle) {
context.fillStyle = this.circle;
context.beginPath();
context.arc(canvas.width / 2, canvas.height / 2, canvas.width / 3, 0, Math.PI * 2);
context.fill();
}
const bufferSize = size / scale;
const batch = this.batch = this.batch || new ContextSpriteBatch(createCanvas(bufferSize, bufferSize));
resizeCanvas(batch.canvas, bufferSize, bufferSize);
const fills = Array.isArray(this.fill) ? this.fill : [this.fill];
const outlines = Array.isArray(this.outline) ? this.outline : [this.outline];
const paletteColors = toColorList(getColorsFromSet({ fills, outlines }, '000000', this.darken));
const palette = mockPaletteManager.addArray(paletteColors);
const extraPalette = sprite.palettes && mockPaletteManager.addArray(sprite.palettes[0]);
let x = this.x;
let y = this.y;
if (this.center) {
const bounds = rect(0, 0, 0, 0);
addRect(bounds, sprite.color);
addRect(bounds, sprite.extra);
if (sprite.colorMany) {
sprite.colorMany.forEach(c => addRect(bounds, c));
}
x = Math.round((bufferSize - bounds.w) / 2 - bounds.x);
y = Math.round((bufferSize - bounds.h) / 2 - bounds.y);
}
batch.start(paletteSpriteSheet, 0);
if (this.reverseExtra) {
batch.drawSprite(sprite.extra, WHITE, extraPalette, x, y);
}
if (sprite.colorMany) {
for (const color of sprite.colorMany) {
batch.drawSprite(color, WHITE, palette, x, y);
}
} else {
batch.drawSprite(sprite.color, WHITE, palette, x, y);
}
if (!this.reverseExtra) {
batch.drawSprite(sprite.extra, WHITE, extraPalette, x, y);
}
batch.end();
disableImageSmoothing(context);
context.scale(scale, scale);
context.drawImage(batch.canvas, 0, 0);
}
context.restore();
}
}
function addRect(rect: Rect, sprite: Sprite | undefined) {
if (sprite && sprite.w && sprite.h) {
if (rect.w === 0 || rect.h === 0) {
rect.x = sprite.ox;
rect.y = sprite.oy;
rect.w = sprite.w;
rect.h = sprite.h;
} else {
const x = Math.min(rect.x, sprite.ox);
const y = Math.min(rect.y, sprite.oy);
rect.w = Math.max(rect.x + rect.w, sprite.ox + sprite.w) - x;
rect.h = Math.max(rect.y + rect.h, sprite.oy + sprite.h) - y;
rect.x = x;
rect.y = y;
}
}
}