UNPKG

dragonbones-runtime

Version:

the tools to build dragonbones file for diffrent framework

422 lines (362 loc) 15.4 kB
////////////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2014-present, Egret Technology. // All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of the Egret nor the // names of its contributors may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY EGRET AND CONTRIBUTORS "AS IS" AND ANY EXPRESS // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL EGRET AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;LOSS OF USE, DATA, // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ////////////////////////////////////////////////////////////////////////////////////// namespace egret.web { /** * @private * WebGL渲染缓存 */ export class WebGLRenderBuffer extends HashObject implements sys.RenderBuffer { public static autoClear: boolean = true; /** * 渲染上下文 */ public context: WebGLRenderContext; /** * 如果是舞台缓存,为canvas * 如果是普通缓存,为renderTarget */ public surface: any; /** * root render target * 根渲染目标,用来执行主渲染 */ public rootRenderTarget: WebGLRenderTarget; /** * 是否为舞台buffer */ private root: boolean; public constructor(width?: number, height?: number, root?: boolean) { super(); // 获取webglRenderContext this.context = WebGLRenderContext.getInstance(width, height); // buffer 对应的 render target this.rootRenderTarget = new WebGLRenderTarget(this.context.context, 3, 3); if (width && height) { this.resize(width, height); } // 如果是第一个加入的buffer,说明是舞台buffer this.root = root; // 如果是用于舞台渲染的renderBuffer,则默认添加renderTarget到renderContext中,而且是第一个 if (this.root) { this.context.pushBuffer(this); // 画布 this.surface = this.context.surface; this.$computeDrawCall = true; } else { // 由于创建renderTarget造成的frameBuffer绑定,这里重置绑定 let lastBuffer = this.context.activatedBuffer; if (lastBuffer) { lastBuffer.rootRenderTarget.activate(); } this.rootRenderTarget.initFrameBuffer(); this.surface = this.rootRenderTarget; } } public globalAlpha: number = 1; /** * stencil state * 模版开关状态 */ private stencilState: boolean = false; public $stencilList: { x:number, y:number, width:number, height:number }[] = []; public stencilHandleCount: number = 0; public enableStencil(): void { if (!this.stencilState) { this.context.enableStencilTest(); this.stencilState = true; } } public disableStencil(): void { if (this.stencilState) { this.context.disableStencilTest(); this.stencilState = false; } } public restoreStencil(): void { if (this.stencilState) { this.context.enableStencilTest(); } else { this.context.disableStencilTest(); } } /** * scissor state * scissor 开关状态 */ public $scissorState: boolean = false; private scissorRect: Rectangle = new egret.Rectangle(); public $hasScissor: boolean = false; public enableScissor(x: number, y: number, width: number, height: number): void { if (!this.$scissorState) { this.$scissorState = true; this.scissorRect.setTo(x, y, width, height); this.context.enableScissorTest(this.scissorRect); } } public disableScissor(): void { if (this.$scissorState) { this.$scissorState = false; this.scissorRect.setEmpty(); this.context.disableScissorTest(); } } public restoreScissor(): void { if (this.$scissorState) { this.context.enableScissorTest(this.scissorRect); } else { this.context.disableScissorTest(); } } /** * 渲染缓冲的宽度,以像素为单位。 * @readOnly */ public get width(): number { return this.rootRenderTarget.width; } /** * 渲染缓冲的高度,以像素为单位。 * @readOnly */ public get height(): number { return this.rootRenderTarget.height; } /** * 改变渲染缓冲的大小并清空缓冲区 * @param width 改变后的宽 * @param height 改变后的高 * @param useMaxSize 若传入true,则将改变后的尺寸与已有尺寸对比,保留较大的尺寸。 */ public resize(width: number, height: number, useMaxSize?: boolean): void { this.context.pushBuffer(this); width = width || 1; height = height || 1; // render target 尺寸重置 if (width != this.rootRenderTarget.width || height != this.rootRenderTarget.height) { this.context.drawCmdManager.pushResize(this, width, height); // 同步更改宽高 this.rootRenderTarget.width = width; this.rootRenderTarget.height = height; } // 如果是舞台的渲染缓冲,执行resize,否则surface大小不随之改变 if (this.root) { this.context.resize(width, height, useMaxSize); } this.context.clear(); this.context.popBuffer(); } /** * 获取指定区域的像素 */ public getPixels(x: number, y: number, width: number = 1, height: number = 1): number[] { let pixels = new Uint8Array(4 * width * height); let useFrameBuffer = this.rootRenderTarget.useFrameBuffer; this.rootRenderTarget.useFrameBuffer = true; this.rootRenderTarget.activate(); this.context.getPixels(x, y, width, height, pixels); this.rootRenderTarget.useFrameBuffer = useFrameBuffer; this.rootRenderTarget.activate(); //图像反转 let result = new Uint8Array(4 * width * height); for (let i = 0; i < height; i++) { for (let j = 0; j < width; j++) { result[(width * (height - i - 1) + j) * 4] = pixels[(width * i + j) * 4]; result[(width * (height - i - 1) + j) * 4 + 1] = pixels[(width * i + j) * 4 + 1]; result[(width * (height - i - 1) + j) * 4 + 2] = pixels[(width * i + j) * 4 + 2]; result[(width * (height - i - 1) + j) * 4 + 3] = pixels[(width * i + j) * 4 + 3]; } } return <number[]><any>result; } /** * 转换成base64字符串,如果图片(或者包含的图片)跨域,则返回null * @param type 转换的类型,如: "image/png","image/jpeg" */ public toDataURL(type?: string, encoderOptions?: number): string { return this.context.surface.toDataURL(type, encoderOptions); } /** * 销毁绘制对象 */ public destroy(): void { this.context.destroy(); } public onRenderFinish(): void { this.$drawCalls = 0; } /** * 交换frameBuffer中的图像到surface中 * @param width 宽度 * @param height 高度 */ private drawFrameBufferToSurface(sourceX: number, sourceY: number, sourceWidth: number, sourceHeight: number, destX: number, destY: number, destWidth: number, destHeight: number, clear: boolean = false): void { this.rootRenderTarget.useFrameBuffer = false; this.rootRenderTarget.activate(); this.context.disableStencilTest();// 切换frameBuffer注意要禁用STENCIL_TEST this.context.disableScissorTest(); this.setTransform(1, 0, 0, 1, 0, 0); this.globalAlpha = 1; this.context.setGlobalCompositeOperation("source-over"); clear && this.context.clear(); this.context.drawImage(<BitmapData><any>this.rootRenderTarget, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight, sourceWidth, sourceHeight, false); this.context.$drawWebGL(); this.rootRenderTarget.useFrameBuffer = true; this.rootRenderTarget.activate(); this.restoreStencil(); this.restoreScissor(); } /** * 交换surface的图像到frameBuffer中 * @param width 宽度 * @param height 高度 */ private drawSurfaceToFrameBuffer(sourceX: number, sourceY: number, sourceWidth: number, sourceHeight: number, destX: number, destY: number, destWidth: number, destHeight: number, clear: boolean = false): void { this.rootRenderTarget.useFrameBuffer = true; this.rootRenderTarget.activate(); this.context.disableStencilTest();// 切换frameBuffer注意要禁用STENCIL_TEST this.context.disableScissorTest(); this.setTransform(1, 0, 0, 1, 0, 0); this.globalAlpha = 1; this.context.setGlobalCompositeOperation("source-over"); clear && this.context.clear(); this.context.drawImage(<BitmapData><any>this.context.surface, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight, sourceWidth, sourceHeight, false); this.context.$drawWebGL(); this.rootRenderTarget.useFrameBuffer = false; this.rootRenderTarget.activate(); this.restoreStencil(); this.restoreScissor(); } /** * 清空缓冲区数据 */ public clear(): void { this.context.pushBuffer(this); this.context.clear(); this.context.popBuffer(); } public $drawCalls: number = 0; public $computeDrawCall: boolean = false; public globalMatrix: Matrix = new Matrix(); public savedGlobalMatrix: Matrix = new Matrix(); public $offsetX: number = 0; public $offsetY: number = 0; public setTransform(a: number, b: number, c: number, d: number, tx: number, ty: number): void { // this.globalMatrix.setTo(a, b, c, d, tx, ty); let matrix = this.globalMatrix; matrix.a = a; matrix.b = b; matrix.c = c; matrix.d = d; matrix.tx = tx; matrix.ty = ty; } public transform(a: number, b: number, c: number, d: number, tx: number, ty: number): void { let matrix = this.globalMatrix; let a1 = matrix.a; let b1 = matrix.b; let c1 = matrix.c; let d1 = matrix.d; if (a != 1 || b != 0 || c != 0 || d != 1) { matrix.a = a * a1 + b * c1; matrix.b = a * b1 + b * d1; matrix.c = c * a1 + d * c1; matrix.d = c * b1 + d * d1; } matrix.tx = tx * a1 + ty * c1 + matrix.tx; matrix.ty = tx * b1 + ty * d1 + matrix.ty; } public translate(dx: number, dy: number): void { let matrix = this.globalMatrix; matrix.tx += dx; matrix.ty += dy; } public useOffset(): void { let self = this; if (self.$offsetX != 0 || self.$offsetY != 0) { self.globalMatrix.append(1, 0, 0, 1, self.$offsetX, self.$offsetY); self.$offsetX = self.$offsetY = 0; } } public saveTransform(): void { let matrix = this.globalMatrix; let sMatrix = this.savedGlobalMatrix; sMatrix.a = matrix.a; sMatrix.b = matrix.b; sMatrix.c = matrix.c; sMatrix.d = matrix.d; sMatrix.tx = matrix.tx; sMatrix.ty = matrix.ty; } public restoreTransform(): void { let matrix = this.globalMatrix; let sMatrix = this.savedGlobalMatrix; matrix.a = sMatrix.a; matrix.b = sMatrix.b; matrix.c = sMatrix.c; matrix.d = sMatrix.d; matrix.tx = sMatrix.tx; matrix.ty = sMatrix.ty; } /** * 创建一个buffer实例 */ public static create(width: number, height: number): WebGLRenderBuffer { let buffer = renderBufferPool.pop(); // width = Math.min(width, 1024); // height = Math.min(height, 1024); if (buffer) { buffer.resize(width, height); var matrix = buffer.globalMatrix; matrix.a = 1; matrix.b = 0; matrix.c = 0; matrix.d = 1; matrix.tx = 0; matrix.ty = 0; buffer.globalAlpha = 1; buffer.$offsetX = 0; buffer.$offsetY = 0; } else { buffer = new WebGLRenderBuffer(width, height); buffer.$computeDrawCall = false; } return buffer; } /** * 回收一个buffer实例 */ public static release(buffer: WebGLRenderBuffer): void { renderBufferPool.push(buffer); } } let renderBufferPool: WebGLRenderBuffer[] = [];//渲染缓冲区对象池 }