mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-04-19 17:16:08 +08:00
refactor: winskin 绘制
This commit is contained in:
parent
b0e420c167
commit
df993a7242
@ -132,7 +132,7 @@ export class Text extends RenderItem<ETextEvent> {
|
|||||||
case 'font':
|
case 'font':
|
||||||
if (!this.assertType(nextValue, 'string', key)) return false;
|
if (!this.assertType(nextValue, 'string', key)) return false;
|
||||||
this.setFont(nextValue);
|
this.setFont(nextValue);
|
||||||
break;
|
return true;
|
||||||
case 'strokeWidth':
|
case 'strokeWidth':
|
||||||
this.setStrokeWidth(nextValue);
|
this.setStrokeWidth(nextValue);
|
||||||
return true;
|
return true;
|
||||||
@ -338,14 +338,27 @@ export class Icon extends RenderItem<EIconEvent> implements IAnimateFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface WinskinPatterns {
|
||||||
|
top: CanvasPattern;
|
||||||
|
left: CanvasPattern;
|
||||||
|
bottom: CanvasPattern;
|
||||||
|
right: CanvasPattern;
|
||||||
|
}
|
||||||
|
|
||||||
export interface EWinskinEvent extends ERenderItemEvent {}
|
export interface EWinskinEvent extends ERenderItemEvent {}
|
||||||
|
|
||||||
export class Winskin extends RenderItem<EWinskinEvent> {
|
export class Winskin extends RenderItem<EWinskinEvent> {
|
||||||
image: SizedCanvasImageSource;
|
image: SizedCanvasImageSource;
|
||||||
/** 边框宽度 */
|
/** 边框宽度,32表示原始宽度 */
|
||||||
borderSize: number = 32;
|
borderSize: number = 32;
|
||||||
|
/** 图片名称 */
|
||||||
|
imageName?: string;
|
||||||
|
|
||||||
private pendingImage?: ImageIds;
|
private pendingImage?: ImageIds;
|
||||||
|
private patternCache?: WinskinPatterns;
|
||||||
|
private patternTransform: DOMMatrix;
|
||||||
|
|
||||||
|
private static patternMap: Map<string, WinskinPatterns> = new Map();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
image: SizedCanvasImageSource,
|
image: SizedCanvasImageSource,
|
||||||
@ -353,6 +366,64 @@ export class Winskin extends RenderItem<EWinskinEvent> {
|
|||||||
) {
|
) {
|
||||||
super(type, false, false);
|
super(type, false, false);
|
||||||
this.image = image;
|
this.image = image;
|
||||||
|
this.setAntiAliasing(false);
|
||||||
|
|
||||||
|
if (window.DOMMatrix) {
|
||||||
|
this.patternTransform = new DOMMatrix();
|
||||||
|
} else if (window.WebKitCSSMatrix) {
|
||||||
|
this.patternTransform = new WebKitCSSMatrix();
|
||||||
|
} else {
|
||||||
|
this.patternTransform = new SVGMatrix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generatePattern() {
|
||||||
|
const pattern = this.requireCanvas();
|
||||||
|
const img = this.image;
|
||||||
|
pattern.size(32, 16);
|
||||||
|
pattern.withGameScale(false);
|
||||||
|
pattern.setHD(false);
|
||||||
|
pattern.setAntiAliasing(false);
|
||||||
|
const ctx = pattern.ctx;
|
||||||
|
ctx.drawImage(img, 144, 0, 32, 16, 0, 0, 32, 16);
|
||||||
|
const topPattern = ctx.createPattern(pattern.canvas, 'repeat');
|
||||||
|
ctx.clearRect(0, 0, 32, 16);
|
||||||
|
ctx.drawImage(img, 144, 48, 32, 16, 0, 0, 32, 16);
|
||||||
|
const bottomPattern = ctx.createPattern(pattern.canvas, 'repeat');
|
||||||
|
ctx.clearRect(0, 0, 32, 16);
|
||||||
|
pattern.size(16, 32);
|
||||||
|
ctx.drawImage(img, 128, 16, 16, 32, 0, 0, 16, 32);
|
||||||
|
const leftPattern = ctx.createPattern(pattern.canvas, 'repeat');
|
||||||
|
ctx.clearRect(0, 0, 16, 32);
|
||||||
|
ctx.drawImage(img, 176, 16, 16, 32, 0, 0, 16, 32);
|
||||||
|
const rightPattern = ctx.createPattern(pattern.canvas, 'repeat');
|
||||||
|
if (!topPattern || !bottomPattern || !leftPattern || !rightPattern) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const winskinPattern: WinskinPatterns = {
|
||||||
|
top: topPattern,
|
||||||
|
bottom: bottomPattern,
|
||||||
|
left: leftPattern,
|
||||||
|
right: rightPattern
|
||||||
|
};
|
||||||
|
if (this.imageName) {
|
||||||
|
Winskin.patternMap.set(this.imageName, winskinPattern);
|
||||||
|
}
|
||||||
|
this.patternCache = winskinPattern;
|
||||||
|
pattern.delete();
|
||||||
|
this.canvases.delete(pattern);
|
||||||
|
return winskinPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getPattern() {
|
||||||
|
if (!this.imageName) {
|
||||||
|
if (this.patternCache) return this.patternCache;
|
||||||
|
return this.generatePattern();
|
||||||
|
} else {
|
||||||
|
const pattern = Winskin.patternMap.get(this.imageName);
|
||||||
|
if (pattern) return pattern;
|
||||||
|
return this.generatePattern();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(
|
protected render(
|
||||||
@ -361,143 +432,38 @@ export class Winskin extends RenderItem<EWinskinEvent> {
|
|||||||
): void {
|
): void {
|
||||||
const ctx = canvas.ctx;
|
const ctx = canvas.ctx;
|
||||||
const img = this.image;
|
const img = this.image;
|
||||||
const x = 0;
|
const w = this.width;
|
||||||
const y = 0;
|
const h = this.height;
|
||||||
const w = canvas.width;
|
const pad = this.borderSize / 2;
|
||||||
const h = canvas.height;
|
// 背景
|
||||||
const sz = this.borderSize / 32;
|
ctx.drawImage(img, 0, 0, 128, 128, 2, 2, w - 4, h - 4);
|
||||||
ctx.drawImage(img, 0, 0, 128, 128, x + 2, y + 2, w - 4, h - 4);
|
const pattern = this.getPattern();
|
||||||
ctx.drawImage(img, 128, 0, 16, 16, x, y, 16 * sz, 16 * sz);
|
if (!pattern) return;
|
||||||
let dx;
|
const { top, left, right, bottom } = pattern;
|
||||||
for (dx = 0; dx < w - 64 * sz; dx += 32 * sz) {
|
top.setTransform(this.patternTransform);
|
||||||
ctx.drawImage(
|
left.setTransform(this.patternTransform);
|
||||||
img,
|
right.setTransform(this.patternTransform);
|
||||||
144,
|
bottom.setTransform(this.patternTransform);
|
||||||
0,
|
// 上下左右边框
|
||||||
32,
|
ctx.save();
|
||||||
16,
|
ctx.fillStyle = top;
|
||||||
x + dx + 16,
|
ctx.translate(pad, 0);
|
||||||
y,
|
ctx.fillRect(0, 0, w - pad * 2, pad);
|
||||||
32 * sz,
|
ctx.fillStyle = bottom;
|
||||||
16 * sz
|
ctx.translate(0, h - pad);
|
||||||
);
|
ctx.fillRect(0, 0, w - pad * 2, pad);
|
||||||
ctx.drawImage(
|
ctx.fillStyle = left;
|
||||||
img,
|
ctx.translate(-pad, pad * 2 - h);
|
||||||
144,
|
ctx.fillRect(0, 0, pad, h - pad * 2);
|
||||||
48,
|
ctx.fillStyle = right;
|
||||||
32,
|
ctx.translate(w - pad, 0);
|
||||||
16,
|
ctx.fillRect(0, 0, pad, h - pad * 2);
|
||||||
x + dx + 16,
|
ctx.restore();
|
||||||
y + h - 16 * sz,
|
// 四个角的边框
|
||||||
32 * sz,
|
ctx.drawImage(img, 128, 0, 16, 16, 0, 0, pad, pad);
|
||||||
16 * sz
|
ctx.drawImage(img, 176, 0, 16, 16, w - pad, 0, pad, pad);
|
||||||
);
|
ctx.drawImage(img, 128, 48, 16, 16, 0, h - pad, pad, pad);
|
||||||
}
|
ctx.drawImage(img, 176, 48, 16, 16, w - pad, h - pad, pad, pad);
|
||||||
ctx.drawImage(
|
|
||||||
img,
|
|
||||||
144,
|
|
||||||
0,
|
|
||||||
w - dx - 32,
|
|
||||||
16,
|
|
||||||
x + dx + 16 * sz,
|
|
||||||
y,
|
|
||||||
w - dx - 32 * sz,
|
|
||||||
16 * sz
|
|
||||||
);
|
|
||||||
ctx.drawImage(
|
|
||||||
img,
|
|
||||||
144,
|
|
||||||
48,
|
|
||||||
w - dx - 32,
|
|
||||||
16,
|
|
||||||
x + dx + 16 * sz,
|
|
||||||
y + h - 16 * sz,
|
|
||||||
w - dx - 32 * sz,
|
|
||||||
16 * sz
|
|
||||||
);
|
|
||||||
ctx.drawImage(
|
|
||||||
img,
|
|
||||||
176,
|
|
||||||
0,
|
|
||||||
16,
|
|
||||||
16,
|
|
||||||
x + w - 16 * sz,
|
|
||||||
y,
|
|
||||||
16 * sz,
|
|
||||||
16 * sz
|
|
||||||
);
|
|
||||||
// 左右
|
|
||||||
let dy;
|
|
||||||
for (dy = 0; dy < h - 64 * sz; dy += 32 * sz) {
|
|
||||||
ctx.drawImage(
|
|
||||||
img,
|
|
||||||
128,
|
|
||||||
16,
|
|
||||||
16,
|
|
||||||
32,
|
|
||||||
x,
|
|
||||||
y + dy + 16 * sz,
|
|
||||||
16 * sz,
|
|
||||||
32 * sz
|
|
||||||
);
|
|
||||||
ctx.drawImage(
|
|
||||||
img,
|
|
||||||
176,
|
|
||||||
16,
|
|
||||||
16,
|
|
||||||
32,
|
|
||||||
x + w - 16 * sz,
|
|
||||||
y + dy + 16 * sz,
|
|
||||||
16 * sz,
|
|
||||||
32 * sz
|
|
||||||
);
|
|
||||||
}
|
|
||||||
ctx.drawImage(
|
|
||||||
img,
|
|
||||||
128,
|
|
||||||
16,
|
|
||||||
16,
|
|
||||||
h - dy - 32,
|
|
||||||
x,
|
|
||||||
y + dy + 16 * sz,
|
|
||||||
16 * sz,
|
|
||||||
h - dy - 32 * sz
|
|
||||||
);
|
|
||||||
ctx.drawImage(
|
|
||||||
img,
|
|
||||||
176,
|
|
||||||
16,
|
|
||||||
16,
|
|
||||||
h - dy - 32,
|
|
||||||
x + w - 16 * sz,
|
|
||||||
y + dy + 16 * sz,
|
|
||||||
16 * sz,
|
|
||||||
h - dy - 32 * sz
|
|
||||||
);
|
|
||||||
// 下方
|
|
||||||
ctx.drawImage(
|
|
||||||
img,
|
|
||||||
128,
|
|
||||||
48,
|
|
||||||
16,
|
|
||||||
16,
|
|
||||||
x,
|
|
||||||
y + h - 16 * sz,
|
|
||||||
16 * sz,
|
|
||||||
16 * sz
|
|
||||||
);
|
|
||||||
ctx.drawImage(
|
|
||||||
img,
|
|
||||||
176,
|
|
||||||
48,
|
|
||||||
16,
|
|
||||||
16,
|
|
||||||
x + w - 16 * sz,
|
|
||||||
y + h - 16 * sz,
|
|
||||||
16 * sz,
|
|
||||||
16 * sz
|
|
||||||
);
|
|
||||||
this.update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -506,6 +472,7 @@ export class Winskin extends RenderItem<EWinskinEvent> {
|
|||||||
*/
|
*/
|
||||||
setImage(image: SizedCanvasImageSource) {
|
setImage(image: SizedCanvasImageSource) {
|
||||||
this.image = image;
|
this.image = image;
|
||||||
|
this.patternCache = void 0;
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,6 +497,7 @@ export class Winskin extends RenderItem<EWinskinEvent> {
|
|||||||
}
|
}
|
||||||
this.pendingImage = name;
|
this.pendingImage = name;
|
||||||
}
|
}
|
||||||
|
this.imageName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -538,6 +506,8 @@ export class Winskin extends RenderItem<EWinskinEvent> {
|
|||||||
*/
|
*/
|
||||||
setBorderSize(size: number) {
|
setBorderSize(size: number) {
|
||||||
this.borderSize = size;
|
this.borderSize = size;
|
||||||
|
this.patternTransform.a = size / 32;
|
||||||
|
this.patternTransform.d = size / 32;
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user