|
@@ -56,11 +56,11 @@ export class TextureCanvasManager {
|
|
|
|
|
|
private _size : ISize;
|
|
|
|
|
|
- /* The canvas we paint onto using the canvas API */
|
|
|
+ /** The canvas we paint onto using the canvas API */
|
|
|
private _2DCanvas : HTMLCanvasElement;
|
|
|
- /* The canvas we apply post processes to */
|
|
|
+ /** The canvas we apply post processes to */
|
|
|
private _3DCanvas : HTMLCanvasElement;
|
|
|
- /* The canvas which handles channel filtering */
|
|
|
+ /** The canvas which handles channel filtering */
|
|
|
private _channelsTexture : HtmlElementTexture;
|
|
|
|
|
|
private _3DEngine : Engine;
|
|
@@ -72,41 +72,45 @@ export class TextureCanvasManager {
|
|
|
private _face : number = 0;
|
|
|
private _mipLevel : number = 0;
|
|
|
|
|
|
- /* The texture from the original engine that we invoked the editor on */
|
|
|
+ /** The texture from the original engine that we invoked the editor on */
|
|
|
private _originalTexture: BaseTexture;
|
|
|
- /* This is a hidden texture which is only responsible for holding the actual texture memory in the original engine */
|
|
|
+ /** This is a hidden texture which is only responsible for holding the actual texture memory in the original engine */
|
|
|
private _target : HtmlElementTexture | RawCubeTexture;
|
|
|
- /* The internal texture representation of the original texture */
|
|
|
+ /** The internal texture representation of the original texture */
|
|
|
private _originalInternalTexture : Nullable<InternalTexture> = null;
|
|
|
- /* Keeps track of whether we have modified the texture */
|
|
|
+ /** Keeps track of whether we have modified the texture */
|
|
|
private _didEdit : boolean = false;
|
|
|
|
|
|
private _plane : Mesh;
|
|
|
private _planeMaterial : ShaderMaterial;
|
|
|
|
|
|
- /* Tracks which keys are currently pressed */
|
|
|
+ /** Tracks which keys are currently pressed */
|
|
|
private _keyMap : any = {};
|
|
|
|
|
|
- private static ZOOM_MOUSE_SPEED : number = 0.001;
|
|
|
- private static ZOOM_KEYBOARD_SPEED : number = 0.4;
|
|
|
- private static ZOOM_IN_KEY : string = '+';
|
|
|
- private static ZOOM_OUT_KEY : string = '-';
|
|
|
+ private readonly ZOOM_MOUSE_SPEED : number = 0.001;
|
|
|
+ private readonly ZOOM_KEYBOARD_SPEED : number = 0.4;
|
|
|
+ private readonly ZOOM_IN_KEY : string = '+';
|
|
|
+ private readonly ZOOM_OUT_KEY : string = '-';
|
|
|
|
|
|
- private static PAN_SPEED : number = 0.002;
|
|
|
- private static PAN_MOUSE_BUTTON : number = 1; // MMB
|
|
|
+ private readonly PAN_SPEED : number = 0.003;
|
|
|
+ private readonly PAN_MOUSE_BUTTON : number = 1; // MMB
|
|
|
|
|
|
- private static MIN_SCALE : number = 0.01;
|
|
|
- private static GRID_SCALE : number = 0.047;
|
|
|
- private static MAX_SCALE : number = 10;
|
|
|
+ private readonly MIN_SCALE : number = 0.01;
|
|
|
+ private readonly GRID_SCALE : number = 0.047;
|
|
|
+ private readonly MAX_SCALE : number = 10;
|
|
|
|
|
|
- private static SELECT_ALL_KEY = 'KeyA';
|
|
|
- private static SAVE_KEY ='KeyS';
|
|
|
- private static RESET_KEY = 'KeyR';
|
|
|
- private static DESELECT_KEY = 'Escape'
|
|
|
+ private readonly SELECT_ALL_KEY = 'KeyA';
|
|
|
+ private readonly SAVE_KEY ='KeyS';
|
|
|
+ private readonly RESET_KEY = 'KeyR';
|
|
|
+ private readonly DESELECT_KEY = 'Escape'
|
|
|
+
|
|
|
+ /** The number of milliseconds between texture updates */
|
|
|
+ private readonly PUSH_FREQUENCY = 32;
|
|
|
|
|
|
private _tool : Nullable<ITool>;
|
|
|
|
|
|
private _setPixelData : (pixelData : IPixelData) => void;
|
|
|
+ private _setMipLevel: (mipLevel: number) => void;
|
|
|
|
|
|
private _window : Window;
|
|
|
|
|
@@ -118,8 +122,8 @@ export class TextureCanvasManager {
|
|
|
private _setMetadata : (metadata: any) => void;
|
|
|
|
|
|
private _imageData : Uint8Array | Uint8ClampedArray;
|
|
|
- private _canUpdate : boolean = true;
|
|
|
- private _shouldUpdate : boolean = false;
|
|
|
+ private _canPush : boolean = true;
|
|
|
+ private _shouldPush : boolean = false;
|
|
|
private _paintCanvas: HTMLCanvasElement;
|
|
|
|
|
|
public constructor(
|
|
@@ -131,7 +135,8 @@ export class TextureCanvasManager {
|
|
|
setPixelData: (pixelData : IPixelData) => void,
|
|
|
metadata: IMetadata,
|
|
|
onUpdate: () => void,
|
|
|
- setMetadata: (metadata: any) => void
|
|
|
+ setMetadata: (metadata: any) => void,
|
|
|
+ setMipLevel: (level: number) => void
|
|
|
) {
|
|
|
this._window = window;
|
|
|
|
|
@@ -143,6 +148,7 @@ export class TextureCanvasManager {
|
|
|
this._metadata = metadata;
|
|
|
this._onUpdate = onUpdate;
|
|
|
this._setMetadata = setMetadata;
|
|
|
+ this._setMipLevel = setMipLevel;
|
|
|
|
|
|
this._size = texture.getSize();
|
|
|
this._originalTexture = texture;
|
|
@@ -201,7 +207,7 @@ export class TextureCanvasManager {
|
|
|
|
|
|
this._window.addEventListener('keydown', evt => {
|
|
|
this._keyMap[evt.code] = true;
|
|
|
- if (evt.code === TextureCanvasManager.SELECT_ALL_KEY && evt.ctrlKey) {
|
|
|
+ if (evt.code === this.SELECT_ALL_KEY && evt.ctrlKey) {
|
|
|
this._setMetadata({
|
|
|
select: {
|
|
|
x1: 0,
|
|
@@ -212,15 +218,15 @@ export class TextureCanvasManager {
|
|
|
});
|
|
|
evt.preventDefault();
|
|
|
}
|
|
|
- if (evt.code === TextureCanvasManager.SAVE_KEY && evt.ctrlKey) {
|
|
|
+ if (evt.code === this.SAVE_KEY && evt.ctrlKey) {
|
|
|
this.saveTexture();
|
|
|
evt.preventDefault();
|
|
|
}
|
|
|
- if (evt.code === TextureCanvasManager.RESET_KEY && evt.ctrlKey) {
|
|
|
+ if (evt.code === this.RESET_KEY && evt.ctrlKey) {
|
|
|
this.reset();
|
|
|
evt.preventDefault();
|
|
|
}
|
|
|
- if (evt.code === TextureCanvasManager.DESELECT_KEY) {
|
|
|
+ if (evt.code === this.DESELECT_KEY) {
|
|
|
this._setMetadata({
|
|
|
select: {
|
|
|
x1: -1,
|
|
@@ -240,15 +246,14 @@ export class TextureCanvasManager {
|
|
|
this._engine.resize();
|
|
|
this._scene.render();
|
|
|
this._planeMaterial.setInt('time', new Date().getTime());
|
|
|
-
|
|
|
});
|
|
|
|
|
|
this._scale = 1.5 / Math.max(this._size.width, this._size.height);
|
|
|
this._isPanning = false;
|
|
|
|
|
|
this._scene.onBeforeRenderObservable.add(() => {
|
|
|
- this._scale = Math.min(Math.max(this._scale, TextureCanvasManager.MIN_SCALE / Math.log2(Math.min(this._size.width, this._size.height))), TextureCanvasManager.MAX_SCALE);
|
|
|
- if (this._scale > TextureCanvasManager.GRID_SCALE) {
|
|
|
+ this._scale = Math.min(Math.max(this._scale, this.MIN_SCALE / Math.log2(Math.min(this._size.width, this._size.height))), this.MAX_SCALE);
|
|
|
+ if (this._scale > this.GRID_SCALE) {
|
|
|
this._planeMaterial.setFloat('showGrid', 1.0);
|
|
|
} else {
|
|
|
this._planeMaterial.setFloat('showGrid', 0.0);
|
|
@@ -265,10 +270,10 @@ export class TextureCanvasManager {
|
|
|
switch (pointerInfo.type) {
|
|
|
case PointerEventTypes.POINTERWHEEL:
|
|
|
const event = pointerInfo.event as MouseWheelEvent;
|
|
|
- this._scale -= (event.deltaY * TextureCanvasManager.ZOOM_MOUSE_SPEED * this._scale);
|
|
|
+ this._scale -= (event.deltaY * this.ZOOM_MOUSE_SPEED * this._scale);
|
|
|
break;
|
|
|
case PointerEventTypes.POINTERDOWN:
|
|
|
- if (pointerInfo.event.button === TextureCanvasManager.PAN_MOUSE_BUTTON) {
|
|
|
+ if (pointerInfo.event.button === this.PAN_MOUSE_BUTTON) {
|
|
|
this._isPanning = true;
|
|
|
this._mouseX = pointerInfo.event.x;
|
|
|
this._mouseY = pointerInfo.event.y;
|
|
@@ -276,14 +281,14 @@ export class TextureCanvasManager {
|
|
|
}
|
|
|
break;
|
|
|
case PointerEventTypes.POINTERUP:
|
|
|
- if (pointerInfo.event.button === TextureCanvasManager.PAN_MOUSE_BUTTON) {
|
|
|
+ if (pointerInfo.event.button === this.PAN_MOUSE_BUTTON) {
|
|
|
this._isPanning = false;
|
|
|
}
|
|
|
break;
|
|
|
case PointerEventTypes.POINTERMOVE:
|
|
|
if (this._isPanning) {
|
|
|
- this._cameraPos.x -= (pointerInfo.event.x - this._mouseX) / this._scale * TextureCanvasManager.PAN_SPEED;
|
|
|
- this._cameraPos.y += (pointerInfo.event.y - this._mouseY) / this._scale * TextureCanvasManager.PAN_SPEED;
|
|
|
+ this._cameraPos.x -= (pointerInfo.event.x - this._mouseX) * this.PAN_SPEED / this._scale;
|
|
|
+ this._cameraPos.y += (pointerInfo.event.y - this._mouseY) * this.PAN_SPEED / this._scale;
|
|
|
this._mouseX = pointerInfo.event.x;
|
|
|
this._mouseY = pointerInfo.event.y;
|
|
|
}
|
|
@@ -303,11 +308,11 @@ export class TextureCanvasManager {
|
|
|
case KeyboardEventTypes.KEYDOWN:
|
|
|
this._keyMap[kbInfo.event.key] = true;
|
|
|
switch (kbInfo.event.key) {
|
|
|
- case TextureCanvasManager.ZOOM_IN_KEY:
|
|
|
- this._scale += TextureCanvasManager.ZOOM_KEYBOARD_SPEED * this._scale;
|
|
|
+ case this.ZOOM_IN_KEY:
|
|
|
+ this._scale += this.ZOOM_KEYBOARD_SPEED * this._scale;
|
|
|
break;
|
|
|
- case TextureCanvasManager.ZOOM_OUT_KEY:
|
|
|
- this._scale -= TextureCanvasManager.ZOOM_KEYBOARD_SPEED * this._scale;
|
|
|
+ case this.ZOOM_OUT_KEY:
|
|
|
+ this._scale -= this.ZOOM_KEYBOARD_SPEED * this._scale;
|
|
|
break;
|
|
|
}
|
|
|
break;
|
|
@@ -320,6 +325,7 @@ export class TextureCanvasManager {
|
|
|
|
|
|
|
|
|
public async updateTexture() {
|
|
|
+ if (this._mipLevel !== 0) await this._setMipLevel(0);
|
|
|
this._didEdit = true;
|
|
|
const element = this._editing3D ? this._3DCanvas : this._2DCanvas;
|
|
|
if (this._editing3D) {
|
|
@@ -336,13 +342,14 @@ export class TextureCanvasManager {
|
|
|
{
|
|
|
engine: this._originalTexture.getScene()?.getEngine()!,
|
|
|
scene: null,
|
|
|
- samplingMode: (this._originalTexture as Texture).samplingMode
|
|
|
+ samplingMode: (this._originalTexture as Texture).samplingMode,
|
|
|
+ generateMipMaps: this._originalInternalTexture?.generateMipMaps
|
|
|
}
|
|
|
);
|
|
|
} else {
|
|
|
(this._target as HtmlElementTexture).element = element;
|
|
|
}
|
|
|
- this.queueTextureUpdate();
|
|
|
+ this.pushTexture();
|
|
|
}
|
|
|
this._originalTexture._texture = this._target._texture;
|
|
|
this._channelsTexture.element = element;
|
|
@@ -350,8 +357,8 @@ export class TextureCanvasManager {
|
|
|
this._onUpdate();
|
|
|
}
|
|
|
|
|
|
- private queueTextureUpdate() {
|
|
|
- if (this._canUpdate) {
|
|
|
+ private pushTexture() {
|
|
|
+ if (this._canPush) {
|
|
|
(this._target as HtmlElementTexture).update((this._originalTexture as Texture).invertY);
|
|
|
this._target._texture?.updateSize(this._size.width, this._size.height);
|
|
|
if (this._editing3D) {
|
|
@@ -359,20 +366,21 @@ export class TextureCanvasManager {
|
|
|
} else {
|
|
|
this._imageData = this._2DCanvas.getContext('2d')!.getImageData(0, 0, this._size.width, this._size.height).data;
|
|
|
}
|
|
|
- this._canUpdate = false;
|
|
|
- this._shouldUpdate = false;
|
|
|
+ this._canPush = false;
|
|
|
+ this._shouldPush = false;
|
|
|
setTimeout(() => {
|
|
|
- this._canUpdate = true;
|
|
|
- if (this._shouldUpdate) {
|
|
|
- this.queueTextureUpdate();
|
|
|
+ this._canPush = true;
|
|
|
+ if (this._shouldPush) {
|
|
|
+ this.pushTexture();
|
|
|
}
|
|
|
- }, 32);
|
|
|
+ }, this.PUSH_FREQUENCY);
|
|
|
} else {
|
|
|
- this._shouldUpdate = true;
|
|
|
+ this._shouldPush = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public startPainting() : CanvasRenderingContext2D {
|
|
|
+ public async startPainting() : Promise<CanvasRenderingContext2D> {
|
|
|
+ if (this._mipLevel != 0) await this._setMipLevel(0);
|
|
|
let x = 0, y = 0, w = this._size.width, h = this._size.height;
|
|
|
if (this._metadata.select.x1 != -1) {
|
|
|
x = this._metadata.select.x1;
|
|
@@ -465,17 +473,17 @@ export class TextureCanvasManager {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public static paintPixelsOnCanvas(pixelData : Uint8Array, canvas: HTMLCanvasElement) {
|
|
|
+ public paintPixelsOnCanvas(pixelData : Uint8Array, canvas: HTMLCanvasElement) {
|
|
|
const ctx = canvas.getContext('2d')!;
|
|
|
const imgData = ctx.createImageData(canvas.width, canvas.height);
|
|
|
imgData.data.set(pixelData);
|
|
|
ctx.putImageData(imgData, 0, 0);
|
|
|
}
|
|
|
|
|
|
- public grabOriginalTexture() {
|
|
|
+ public async grabOriginalTexture() {
|
|
|
// Grab image data from original texture and paint it onto the context of a DynamicTexture
|
|
|
this.setSize(this._originalTexture.getSize());
|
|
|
- TextureHelper.GetTextureDataAsync(
|
|
|
+ const data = await TextureHelper.GetTextureDataAsync(
|
|
|
this._originalTexture,
|
|
|
this._size.width,
|
|
|
this._size.height,
|
|
@@ -483,13 +491,13 @@ export class TextureCanvasManager {
|
|
|
{R:true, G:true, B:true, A:true},
|
|
|
undefined,
|
|
|
this._mipLevel
|
|
|
- ).then(data => {
|
|
|
- this._imageData = data;
|
|
|
- TextureCanvasManager.paintPixelsOnCanvas(data, this._2DCanvas);
|
|
|
- this._3DCanvasTexture.update();
|
|
|
- this.updateDisplay();
|
|
|
- })
|
|
|
- }
|
|
|
+ );
|
|
|
+ this._imageData = data;
|
|
|
+ this.paintPixelsOnCanvas(data, this._2DCanvas);
|
|
|
+ this._3DCanvasTexture.update();
|
|
|
+ this.updateDisplay();
|
|
|
+ return data;
|
|
|
+}
|
|
|
|
|
|
public getMouseCoordinates(pointerInfo : PointerInfo) {
|
|
|
if (pointerInfo.pickInfo?.hit) {
|
|
@@ -587,7 +595,7 @@ export class TextureCanvasManager {
|
|
|
public async resize(newSize : ISize) {
|
|
|
const data = await TextureHelper.GetTextureDataAsync(this._originalTexture, newSize.width, newSize.height, this._face, {R: true,G: true,B: true,A: true});
|
|
|
this.setSize(newSize);
|
|
|
- TextureCanvasManager.paintPixelsOnCanvas(data, this._2DCanvas);
|
|
|
+ this.paintPixelsOnCanvas(data, this._2DCanvas);
|
|
|
this.updateTexture();
|
|
|
this._didEdit = true;
|
|
|
}
|
|
@@ -634,14 +642,15 @@ export class TextureCanvasManager {
|
|
|
Texture.NEAREST_SAMPLINGMODE,
|
|
|
() => {
|
|
|
TextureHelper.GetTextureDataAsync(texture, texture.getSize().width, texture.getSize().height, 0, {R: true, G: true, B: true, A: true})
|
|
|
- .then((pixels) => {
|
|
|
+ .then(async (pixels) => {
|
|
|
if (this._tool && this._tool.instance.onReset) {
|
|
|
this._tool.instance.onReset();
|
|
|
}
|
|
|
- this.setSize(texture.getSize());
|
|
|
- TextureCanvasManager.paintPixelsOnCanvas(pixels, this._2DCanvas);
|
|
|
- this.updateTexture();
|
|
|
texture.dispose();
|
|
|
+ this.setSize(texture.getSize());
|
|
|
+ this.paintPixelsOnCanvas(pixels, this._2DCanvas);
|
|
|
+ await this.updateTexture();
|
|
|
+ this._setMipLevel(0);
|
|
|
});
|
|
|
}
|
|
|
);
|