Merge branch 'master' of github.com:bs-community/skinview3d
Added Animated Capes
This commit is contained in:
commit
a3155138d0
|
@ -9,3 +9,4 @@ extends:
|
|||
rules:
|
||||
'@typescript-eslint/no-inferrable-types': off
|
||||
'@typescript-eslint/interface-name-prefix': off
|
||||
'@typescript-eslint/no-empty-interface': off
|
||||
|
|
27
README.md
27
README.md
|
@ -20,21 +20,24 @@ Three.js powered Minecraft skin viewer.
|
|||
```html
|
||||
<div id="skin_container"></div>
|
||||
<script>
|
||||
let skinViewer = new skinview3d.SkinViewer({
|
||||
domElement: document.getElementById("skin_container"),
|
||||
width: 600,
|
||||
height: 600,
|
||||
skinUrl: "img/skin.png",
|
||||
capeUrl: "img/cape.png"
|
||||
let skinViewer = new skinview3d.SkinViewer(document.getElementById("skin_container"), {
|
||||
width: 300,
|
||||
height: 400,
|
||||
skin: "img/skin.png"
|
||||
});
|
||||
|
||||
// Change the textures
|
||||
skinViewer.skinUrl = "img/skin2.png";
|
||||
skinViewer.capeUrl = "img/cape2.png";
|
||||
// Change viewer size
|
||||
skinViewer.width = 600;
|
||||
skinViewer.height = 800;
|
||||
|
||||
// Resize the skin viewer
|
||||
skinViewer.width = 300;
|
||||
skinViewer.height = 400;
|
||||
// Load another skin
|
||||
skinViewer.loadSkin("img/skin2.png");
|
||||
|
||||
// Load a cape
|
||||
skinViewer.loadCape("img/cape.png");
|
||||
|
||||
// Unload(hide) the cape
|
||||
skinViewer.loadCape(null);
|
||||
|
||||
// Control objects with your mouse!
|
||||
let control = skinview3d.createOrbitControls(skinViewer);
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 80 KiB |
|
@ -13,40 +13,59 @@
|
|||
background-color: #1e1e1e;
|
||||
}
|
||||
|
||||
#skin-container {
|
||||
#skin_container {
|
||||
text-align: center;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
#skin-container > canvas {
|
||||
#skin_container > canvas {
|
||||
background: white;
|
||||
filter: drop-shadow(-5px 5px 7px rgba(0, 0, 0, 0.4));
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#elytra, #animated {
|
||||
display: block;
|
||||
margin: 1vh auto;
|
||||
font-size: 2rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="skin-container"></div>
|
||||
|
||||
<button id="elytra">Enable/Disable Elytra</button>
|
||||
<button id="animated">Enable/Disable Animated</button>
|
||||
<div id="skin_container"></div>
|
||||
<script type="text/javascript" src="../bundles/skinview3d.bundle.js"></script>
|
||||
|
||||
<script>
|
||||
let skinViewer = new skinview3d.SkinViewer({
|
||||
domElement: document.getElementById("skin-container"),
|
||||
width: 200,
|
||||
height: 400,
|
||||
skinUrl: "./skin.png",
|
||||
capeUrl: "./cape.png",
|
||||
earUrl: "./ears.png"
|
||||
var animated = false;
|
||||
|
||||
document.getElementById("elytra").addEventListener('click', function() {
|
||||
skinViewer.playerObject.cape.visible = !skinViewer.playerObject.cape.visible;
|
||||
skinViewer.playerObject.elytra.visible = !skinViewer.playerObject.elytra.visible
|
||||
});
|
||||
|
||||
let control = skinview3d.createOrbitControls(skinViewer);
|
||||
control.enableRotate = true;
|
||||
document.getElementById("animated").addEventListener('click', function() {
|
||||
if(animated) {
|
||||
skinViewer.loadCustomCape("./cape.png");
|
||||
animated = false;
|
||||
} else {
|
||||
skinViewer.loadCustomCape("./animated.png");
|
||||
animated = true;
|
||||
}
|
||||
});
|
||||
|
||||
let skinViewer = new skinview3d.SkinViewer(document.getElementById("skin_container"), {
|
||||
width: 1400,
|
||||
height: 800,
|
||||
skin: "./skin.png",
|
||||
cape: "./cape.png",
|
||||
ears: "./ears.png"
|
||||
});
|
||||
|
||||
let control = new skinview3d.createOrbitControls(skinViewer);
|
||||
control.enableZoom = false;
|
||||
control.enablePan = false;
|
||||
|
||||
skinViewer.playerObject.rotation.y = 180 * Math.PI / 180;
|
||||
</script>
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
32
package.json
32
package.json
|
@ -1,17 +1,17 @@
|
|||
{
|
||||
"name": "skinview3d",
|
||||
"version": "2.0.0-alpha.1",
|
||||
"version": "2.0.0-alpha.5",
|
||||
"description": "Three.js powered Minecraft skin viewer",
|
||||
"main": "libs/skinview3d.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"clean": "rimraf libs bundles",
|
||||
"build:modules": "tsc -p .",
|
||||
"build:modules": "tsc --declaration --sourceMap --outDir libs -p .",
|
||||
"build:bundles": "rollup -c",
|
||||
"build": "npm run build:modules && npm run build:bundles",
|
||||
"test:lint": "eslint --ext .ts src",
|
||||
"test": "npm run test:lint",
|
||||
"dev:watch:modules": "tsc -w -p .",
|
||||
"dev:watch:modules": "tsc -w --declaration --sourceMap --outDir libs -p .",
|
||||
"dev:watch:bundles": "rollup -w -c",
|
||||
"dev:serve": "ws",
|
||||
"dev": "npm-run-all --parallel dev:watch:modules dev:watch:bundles dev:serve",
|
||||
|
@ -38,21 +38,21 @@
|
|||
"bundles"
|
||||
],
|
||||
"dependencies": {
|
||||
"three": "^0.112.1",
|
||||
"skinview-utils": "^0.2.0"
|
||||
"skinview-utils": "^0.5.5",
|
||||
"three": "^0.117.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^7.0.0",
|
||||
"@rollup/plugin-typescript": "^2.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^2.17.0",
|
||||
"@typescript-eslint/parser": "^2.17.0",
|
||||
"@yushijinhun/three-minifier-rollup": "^0.1.4",
|
||||
"eslint": "^6.8.0",
|
||||
"local-web-server": "^3.0.7",
|
||||
"@rollup/plugin-node-resolve": "^8.1.0",
|
||||
"@rollup/plugin-typescript": "^5.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^3.4.0",
|
||||
"@typescript-eslint/parser": "^3.4.0",
|
||||
"@yushijinhun/three-minifier-rollup": "^0.1.7",
|
||||
"eslint": "^7.3.1",
|
||||
"local-web-server": "^4.2.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"rimraf": "^3.0.0",
|
||||
"rollup": "^1.29.1",
|
||||
"rollup-plugin-terser": "^5.2.0",
|
||||
"typescript": "^3.7.5"
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^2.18.0",
|
||||
"rollup-plugin-terser": "^6.1.0",
|
||||
"typescript": "^3.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ export class CompositeAnimation implements IAnimation {
|
|||
export class RootAnimation extends CompositeAnimation implements AnimationHandle {
|
||||
speed: number = 1.0;
|
||||
progress: number = 0.0;
|
||||
readonly clock: Clock = new Clock(true);
|
||||
private readonly clock: Clock = new Clock(true);
|
||||
|
||||
get animation(): RootAnimation {
|
||||
return this;
|
||||
|
|
24
src/model.ts
24
src/model.ts
|
@ -1,4 +1,5 @@
|
|||
import { BoxGeometry, DoubleSide, FrontSide, Group, Mesh, MeshBasicMaterial, Object3D, Texture, Vector2, Vector3 } from "three";
|
||||
import { ModelType } from "skinview-utils";
|
||||
import { BoxGeometry, DoubleSide, FrontSide, Group, Mesh, MeshBasicMaterial, Object3D, Texture, Vector2 } from "three";
|
||||
|
||||
function toFaceVertices(x1: number, y1: number, x2: number, y2: number, w: number, h: number): Array<Vector2> {
|
||||
return [
|
||||
|
@ -26,7 +27,6 @@ function toEarVertices(x1: number, y1: number, x2: number, y2: number): Array<Ve
|
|||
}
|
||||
|
||||
function setVertices(box: BoxGeometry, top: Array<Vector2>, bottom: Array<Vector2>, left: Array<Vector2>, front: Array<Vector2>, right: Array<Vector2>, back: Array<Vector2>): void {
|
||||
|
||||
box.faceVertexUvs[0] = [];
|
||||
box.faceVertexUvs[0][0] = [right[3], right[0], right[2]];
|
||||
box.faceVertexUvs[0][1] = [right[0], right[1], right[2]];
|
||||
|
@ -67,7 +67,7 @@ export class SkinObject extends Group {
|
|||
readonly leftLeg: BodyPart;
|
||||
|
||||
private modelListeners: Array<() => void> = []; // called when model(slim property) is changed
|
||||
private _slim = false;
|
||||
private slim = false;
|
||||
|
||||
constructor(texture: Texture) {
|
||||
super();
|
||||
|
@ -218,12 +218,12 @@ export class SkinObject extends Group {
|
|||
|
||||
const rightArmPivot = new Group();
|
||||
rightArmPivot.add(rightArmMesh, rightArm2Mesh);
|
||||
rightArmPivot.position.y = -6;
|
||||
rightArmPivot.position.y = -4;
|
||||
|
||||
this.rightArm = new BodyPart(rightArmMesh, rightArm2Mesh);
|
||||
this.rightArm.name = "rightArm";
|
||||
this.rightArm.add(rightArmPivot);
|
||||
this.rightArm.position.y = -4;
|
||||
this.rightArm.position.y = -6;
|
||||
this.modelListeners.push(() => {
|
||||
this.rightArm.position.x = this.slim ? -5.5 : -6;
|
||||
});
|
||||
|
@ -291,12 +291,12 @@ export class SkinObject extends Group {
|
|||
|
||||
const leftArmPivot = new Group();
|
||||
leftArmPivot.add(leftArmMesh, leftArm2Mesh);
|
||||
leftArmPivot.position.y = -6;
|
||||
leftArmPivot.position.y = -4;
|
||||
|
||||
this.leftArm = new BodyPart(leftArmMesh, leftArm2Mesh);
|
||||
this.leftArm.name = "leftArm";
|
||||
this.leftArm.add(leftArmPivot);
|
||||
this.leftArm.position.y = -4;
|
||||
this.leftArm.position.y = -6;
|
||||
this.modelListeners.push(() => {
|
||||
this.leftArm.position.x = this.slim ? 5.5 : 6;
|
||||
});
|
||||
|
@ -372,15 +372,15 @@ export class SkinObject extends Group {
|
|||
this.leftLeg.position.x = 2;
|
||||
this.add(this.leftLeg);
|
||||
|
||||
this.slim = false;
|
||||
this.modelType = "default";
|
||||
}
|
||||
|
||||
get slim(): boolean {
|
||||
return this._slim;
|
||||
get modelType(): ModelType {
|
||||
return this.slim ? "slim" : "default";
|
||||
}
|
||||
|
||||
set slim(value) {
|
||||
this._slim = value;
|
||||
set modelType(value: ModelType) {
|
||||
this.slim = value === "slim";
|
||||
this.modelListeners.forEach(listener => listener());
|
||||
}
|
||||
|
||||
|
|
302
src/viewer.ts
302
src/viewer.ts
|
@ -1,80 +1,89 @@
|
|||
import { applyMixins, CapeContainer, ModelType, SkinContainer, RemoteImage, TextureSource, TextureCanvas, loadImage, isTextureSource } from "skinview-utils";
|
||||
import { NearestFilter, PerspectiveCamera, Scene, Texture, Vector2, WebGLRenderer } from "three";
|
||||
import { RootAnimation } from "./animation.js";
|
||||
import { PlayerObject } from "./model.js";
|
||||
import { TextureCanvas, TextureSource, isSlimSkin, loadCapeToCanvas, loadSkinToCanvas } from "skinview-utils";
|
||||
|
||||
export interface SkinViewerOptions {
|
||||
domElement: Node;
|
||||
skinUrl?: string;
|
||||
capeUrl?: string;
|
||||
earUrl?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
detectModel?: boolean;
|
||||
export type LoadOptions = {
|
||||
/**
|
||||
* Whether to make the object visible after the texture is loaded. (default: true)
|
||||
*/
|
||||
makeVisible?: boolean;
|
||||
}
|
||||
|
||||
export class SkinViewer {
|
||||
export type SkinViewerOptions = {
|
||||
width?: number;
|
||||
height?: number;
|
||||
skin?: RemoteImage | TextureSource;
|
||||
cape?: RemoteImage | TextureSource;
|
||||
ears?: RemoteImage | TextureSource;
|
||||
}
|
||||
|
||||
public readonly domElement: Node;
|
||||
public readonly animations: RootAnimation = new RootAnimation();
|
||||
public detectModel: boolean = true;
|
||||
function toMakeVisible(options?: LoadOptions): boolean {
|
||||
if (options && options.makeVisible === false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public readonly skinImg: HTMLImageElement;
|
||||
public readonly skinCanvas: HTMLCanvasElement;
|
||||
public readonly skinTexture: Texture;
|
||||
class SkinViewer {
|
||||
readonly domElement: Node;
|
||||
readonly scene: Scene;
|
||||
readonly camera: PerspectiveCamera;
|
||||
readonly renderer: WebGLRenderer;
|
||||
readonly playerObject: PlayerObject;
|
||||
readonly animations: RootAnimation = new RootAnimation();
|
||||
|
||||
public readonly capeImg: HTMLImageElement;
|
||||
public readonly capeCanvas: HTMLCanvasElement;
|
||||
public readonly capeTexture: Texture;
|
||||
protected readonly skinCanvas: HTMLCanvasElement;
|
||||
protected readonly capeCanvas: HTMLCanvasElement;
|
||||
protected readonly earCanvas: HTMLCanvasElement;
|
||||
private readonly skinTexture: Texture;
|
||||
private readonly capeTexture: Texture;
|
||||
private readonly earTexture: Texture;
|
||||
|
||||
public readonly earImg: HTMLImageElement;
|
||||
public readonly earCanvas: HTMLCanvasElement;
|
||||
public readonly earTexture: Texture;
|
||||
|
||||
public readonly scene: Scene;
|
||||
public readonly camera: PerspectiveCamera;
|
||||
public readonly renderer: WebGLRenderer;
|
||||
|
||||
public readonly playerObject: PlayerObject;
|
||||
// Animated Capes (MinecraftCapes)
|
||||
private customCapeImage: TextureSource
|
||||
private lastFrame: number;
|
||||
private maxFrames: number;
|
||||
private lastFrameTime: number;
|
||||
private capeInterval: number;
|
||||
|
||||
private _disposed: boolean = false;
|
||||
private _renderPaused: boolean = false;
|
||||
private _skinSet: boolean = false;
|
||||
private _capeSet: boolean = false;
|
||||
private _earSet: boolean = false;
|
||||
|
||||
constructor(options: SkinViewerOptions) {
|
||||
this.domElement = options.domElement;
|
||||
if (options.detectModel === false) {
|
||||
this.detectModel = false;
|
||||
}
|
||||
constructor(domElement: Node, options: SkinViewerOptions = {}) {
|
||||
this.domElement = domElement;
|
||||
|
||||
// texture
|
||||
this.skinImg = new Image();
|
||||
this.skinCanvas = document.createElement("canvas");
|
||||
this.skinTexture = new Texture(this.skinCanvas);
|
||||
this.skinTexture.magFilter = NearestFilter;
|
||||
this.skinTexture.minFilter = NearestFilter;
|
||||
|
||||
this.capeImg = new Image();
|
||||
this.capeCanvas = document.createElement("canvas");
|
||||
this.capeTexture = new Texture(this.capeCanvas);
|
||||
this.capeTexture.magFilter = NearestFilter;
|
||||
this.capeTexture.minFilter = NearestFilter;
|
||||
|
||||
this.earImg = new Image();
|
||||
this.earCanvas = document.createElement("canvas");
|
||||
this.earTexture = new Texture(this.earCanvas);
|
||||
this.earTexture.magFilter = NearestFilter;
|
||||
this.earTexture.minFilter = NearestFilter;
|
||||
|
||||
// Animated Capes (MinecraftCapes)
|
||||
this.customCapeImage = new Image()
|
||||
this.lastFrame = 0,
|
||||
this.maxFrames = 1,
|
||||
this.lastFrameTime = 0,
|
||||
this.capeInterval = 100,
|
||||
|
||||
// scene
|
||||
this.scene = new Scene();
|
||||
|
||||
// Use smaller fov to avoid distortion
|
||||
this.camera = new PerspectiveCamera(20);
|
||||
this.camera.position.y = 0;
|
||||
this.camera.position.z = 140;
|
||||
this.camera = new PerspectiveCamera(42);
|
||||
this.camera.zoom
|
||||
this.camera.position.y = -12;
|
||||
this.camera.position.z = 60;
|
||||
|
||||
this.renderer = new WebGLRenderer({ alpha: true, logarithmicDepthBuffer: true });
|
||||
this.domElement.appendChild(this.renderer.domElement);
|
||||
|
@ -86,51 +95,57 @@ export class SkinViewer {
|
|||
this.playerObject.ears.visible = false;
|
||||
this.scene.add(this.playerObject);
|
||||
|
||||
// texture loading
|
||||
this.skinImg.crossOrigin = "anonymous";
|
||||
this.skinImg.onerror = (): void => console.error("Failed loading " + this.skinImg.src);
|
||||
this.skinImg.onload = (): void => {
|
||||
loadSkinToCanvas(this.skinCanvas, this.skinImg);
|
||||
|
||||
if (this.detectModel) {
|
||||
this.playerObject.skin.slim = isSlimSkin(this.skinCanvas);
|
||||
}
|
||||
|
||||
this.skinTexture.needsUpdate = true;
|
||||
this.playerObject.skin.visible = true;
|
||||
};
|
||||
|
||||
this.capeImg.crossOrigin = "anonymous";
|
||||
this.capeImg.onerror = (): void => console.error("Failed loading " + this.capeImg.src);
|
||||
this.capeImg.onload = (): void => {
|
||||
loadCapeToCanvas(this.capeCanvas, this.capeImg);
|
||||
|
||||
this.capeTexture.needsUpdate = true;
|
||||
this.playerObject.cape.visible = true;
|
||||
};
|
||||
|
||||
this.earImg.crossOrigin = "anonymous";
|
||||
this.earImg.onerror = (): void => console.error("Failed loading " + this.earImg.src);
|
||||
this.earImg.onload = (): void => {
|
||||
loadEarsToCanvas(this.earCanvas, this.earImg);
|
||||
|
||||
this.earTexture.needsUpdate = true;
|
||||
this.playerObject.ears.visible = true;
|
||||
};
|
||||
|
||||
if (options.skinUrl !== undefined) {
|
||||
this.skinUrl = options.skinUrl;
|
||||
}
|
||||
if (options.capeUrl !== undefined) {
|
||||
this.capeUrl = options.capeUrl;
|
||||
}
|
||||
if (options.earUrl !== undefined) {
|
||||
this.earUrl = options.earUrl;
|
||||
}
|
||||
this.width = options.width === undefined ? 300 : options.width;
|
||||
this.height = options.height === undefined ? 300 : options.height;
|
||||
|
||||
window.requestAnimationFrame(() => this.draw());
|
||||
|
||||
if (options.skin !== undefined) {
|
||||
this.loadSkin(options.skin);
|
||||
}
|
||||
if (options.cape !== undefined) {
|
||||
this.loadCustomCape(options.cape);
|
||||
}
|
||||
if (options.ears !== undefined) {
|
||||
this.loadEars(options.ears);
|
||||
}
|
||||
if (options.width !== undefined) {
|
||||
this.width = options.width;
|
||||
}
|
||||
if (options.height !== undefined) {
|
||||
this.height = options.height;
|
||||
}
|
||||
}
|
||||
|
||||
protected skinLoaded(model: ModelType, options?: LoadOptions): void {
|
||||
this.skinTexture.needsUpdate = true;
|
||||
this.playerObject.skin.modelType = model;
|
||||
if (toMakeVisible(options)) {
|
||||
this.playerObject.skin.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected capeLoaded(options?: LoadOptions): void {
|
||||
this.capeTexture.needsUpdate = true;
|
||||
if (toMakeVisible(options)) {
|
||||
this.playerObject.cape.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected earsLoaded(options?: LoadOptions): void {
|
||||
this.earTexture.needsUpdate = true;
|
||||
if (toMakeVisible(options)) {
|
||||
this.playerObject.ears.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected resetSkin(): void {
|
||||
this.playerObject.skin.visible = false;
|
||||
}
|
||||
|
||||
protected resetCape(): void {
|
||||
this.playerObject.cape.visible = false;
|
||||
}
|
||||
|
||||
protected resetEars(): void {
|
||||
this.playerObject.ears.visible = false;
|
||||
}
|
||||
|
||||
private draw(): void {
|
||||
|
@ -139,6 +154,7 @@ export class SkinViewer {
|
|||
}
|
||||
this.animations.runAnimationLoop(this.playerObject);
|
||||
this.doRender();
|
||||
this.animatedCape();
|
||||
window.requestAnimationFrame(() => this.draw());
|
||||
}
|
||||
|
||||
|
@ -176,48 +192,6 @@ export class SkinViewer {
|
|||
}
|
||||
}
|
||||
|
||||
get skinUrl(): string | null {
|
||||
return this._skinSet ? this.skinImg.src : null;
|
||||
}
|
||||
|
||||
set skinUrl(url: string | null) {
|
||||
if (url === null) {
|
||||
this._skinSet = false;
|
||||
this.playerObject.skin.visible = false;
|
||||
} else {
|
||||
this._skinSet = true;
|
||||
this.skinImg.src = url;
|
||||
}
|
||||
}
|
||||
|
||||
get capeUrl(): string | null {
|
||||
return this._capeSet ? this.capeImg.src : null;
|
||||
}
|
||||
|
||||
set capeUrl(url: string | null) {
|
||||
if (url === null) {
|
||||
this._capeSet = false;
|
||||
this.playerObject.cape.visible = false;
|
||||
} else {
|
||||
this._capeSet = true;
|
||||
this.capeImg.src = url;
|
||||
}
|
||||
}
|
||||
|
||||
get earUrl(): string | null {
|
||||
return this._earSet ? this.earImg.src : null;
|
||||
}
|
||||
|
||||
set earUrl(url: string | null) {
|
||||
if (url === null) {
|
||||
this._earSet = false;
|
||||
this.playerObject.ears.visible = false;
|
||||
} else {
|
||||
this._earSet = true;
|
||||
this.earImg.src = url;
|
||||
}
|
||||
}
|
||||
|
||||
get width(): number {
|
||||
return this.renderer.getSize(new Vector2()).width;
|
||||
}
|
||||
|
@ -233,13 +207,69 @@ export class SkinViewer {
|
|||
set height(newHeight: number) {
|
||||
this.setSize(this.width, newHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Code for MinecraftCapes
|
||||
*/
|
||||
protected loadCustomCape(source: TextureSource | RemoteImage | null): void | Promise<void> {
|
||||
if(source === null) {
|
||||
this.resetCape();
|
||||
} else if(isTextureSource(source)) {
|
||||
this.customCapeImage = source;
|
||||
this.loadCapeToCanvas(this.capeCanvas, source, 0);
|
||||
this.capeLoaded();
|
||||
} else {
|
||||
return loadImage(source).then(image => this.loadCustomCape(image));
|
||||
}
|
||||
}
|
||||
|
||||
protected loadCapeToCanvas(canvas: TextureCanvas, image: TextureSource, offset: number): void {
|
||||
canvas.width = image.width,
|
||||
canvas.height = image.width / 2;
|
||||
var frame = canvas.getContext("2d");
|
||||
if(frame != null) {
|
||||
frame.clearRect(0, 0, canvas.width, canvas.height),
|
||||
frame.drawImage(image, 0, offset, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height)
|
||||
}
|
||||
}
|
||||
|
||||
protected animatedCape() {
|
||||
if (this.customCapeImage.height !== this.customCapeImage.width / 2) {
|
||||
let currentTime = Date.now();
|
||||
if (currentTime > this.lastFrameTime + this.capeInterval) {
|
||||
this.maxFrames = this.customCapeImage.height / (this.customCapeImage.width / 2);
|
||||
let currentFrame = this.lastFrame + 1 > this.maxFrames - 1 ? 0 : this.lastFrame + 1;
|
||||
this.lastFrame = currentFrame,
|
||||
this.lastFrameTime = currentTime;
|
||||
let offset = currentFrame * (this.customCapeImage.width / 2);
|
||||
this.loadCapeToCanvas(this.capeCanvas, this.customCapeImage, offset),
|
||||
this.capeTexture.needsUpdate = true
|
||||
this.playerObject.cape.visible = !this.playerObject.elytra.visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public loadEars(source: TextureSource | RemoteImage | null): void | Promise<void> {
|
||||
if(source === null) {
|
||||
this.resetEars();
|
||||
} else if(isTextureSource(source)) {
|
||||
this.loadEarsToCanvas(this.earCanvas, source);
|
||||
this.earsLoaded();
|
||||
} else {
|
||||
return loadImage(source).then(image => this.loadEars(image));
|
||||
}
|
||||
}
|
||||
|
||||
protected loadEarsToCanvas(canvas: TextureCanvas, image: TextureSource): void {
|
||||
canvas.width = 14;
|
||||
canvas.height = 7;
|
||||
|
||||
const context = canvas.getContext("2d")!;
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
context.drawImage(image, 0, 0, image.width, image.height);
|
||||
}
|
||||
}
|
||||
|
||||
function loadEarsToCanvas(canvas: TextureCanvas, image: TextureSource): void {
|
||||
canvas.width = 14;
|
||||
canvas.height = 7;
|
||||
|
||||
const context = canvas.getContext("2d")!;
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
context.drawImage(image, 0, 0, image.width, image.height);
|
||||
}
|
||||
interface SkinViewer extends SkinContainer<LoadOptions>, CapeContainer<LoadOptions> { }
|
||||
applyMixins(SkinViewer, [SkinContainer, CapeContainer]);
|
||||
export { SkinViewer };
|
|
@ -2,16 +2,11 @@
|
|||
"compilerOptions": {
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"target": "es2017",
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2015"
|
||||
"dom"
|
||||
],
|
||||
"target": "es2015",
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "libs",
|
||||
"types": []
|
||||
"strict": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
|
|
Loading…
Reference in New Issue