dragonbones-runtime
Version:
the tools to build dragonbones file for diffrent framework
1,031 lines (971 loc) • 45.9 kB
text/typescript
//////////////////////////////////////////////////////////////////////////////////////
//
// 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 {
let blendModes = ["source-over", "lighter", "destination-out"];
let defaultCompositeOp = "source-over";
let BLACK_COLOR = "#000000";
let CAPS_STYLES = { none: 'butt', square: 'square', round: 'round' };
let renderBufferPool: WebGLRenderBuffer[] = [];//渲染缓冲区对象池
/**
* @private
* WebGL渲染器
*/
export class WebGLRenderer implements sys.SystemRenderer {
public constructor() {
}
private nestLevel: number = 0;//渲染的嵌套层次,0表示在调用堆栈的最外层。
/**
* 渲染一个显示对象
* @param displayObject 要渲染的显示对象
* @param buffer 渲染缓冲
* @param matrix 要对显示对象整体叠加的变换矩阵
* @param dirtyList 脏矩形列表
* @param forRenderTexture 绘制目标是RenderTexture的标志
* @returns drawCall触发绘制的次数
*/
public render(displayObject: DisplayObject, buffer: sys.RenderBuffer, matrix: Matrix, forRenderTexture?: boolean): number {
this.nestLevel++;
let webglBuffer: WebGLRenderBuffer = <WebGLRenderBuffer>buffer;
let webglBufferContext: WebGLRenderContext = webglBuffer.context;
let root: DisplayObject = forRenderTexture ? displayObject : null;
webglBufferContext.pushBuffer(webglBuffer);
//绘制显示对象
webglBuffer.transform(matrix.a, matrix.b, matrix.c, matrix.d, 0, 0);
this.drawDisplayObject(displayObject, webglBuffer, matrix.tx, matrix.ty, true);
webglBufferContext.$drawWebGL();
let drawCall = webglBuffer.$drawCalls;
webglBuffer.onRenderFinish();
webglBufferContext.popBuffer();
let invert = Matrix.create();
matrix.$invertInto(invert);
webglBuffer.transform(invert.a, invert.b, invert.c, invert.d, 0, 0);
Matrix.release(invert);
this.nestLevel--;
if (this.nestLevel === 0) {
//最大缓存6个渲染缓冲
if (renderBufferPool.length > 6) {
renderBufferPool.length = 6;
}
let length = renderBufferPool.length;
for (let i = 0; i < length; i++) {
renderBufferPool[i].resize(0, 0);
}
}
return drawCall;
}
/**
* @private
* 绘制一个显示对象
*/
private drawDisplayObject(displayObject: DisplayObject, buffer: WebGLRenderBuffer, offsetX: number, offsetY: number, isStage?: boolean): number {
let drawCalls = 0;
let node: sys.RenderNode;
let displayList = displayObject.$displayList;
if (displayList && !isStage) {
if (displayObject.$cacheDirty || displayObject.$renderDirty ||
displayList.$canvasScaleX != sys.DisplayList.$canvasScaleX ||
displayList.$canvasScaleY != sys.DisplayList.$canvasScaleY) {
drawCalls += displayList.drawToSurface();
}
node = displayList.$renderNode;
}
else {
if (displayObject.$renderDirty) {
node = displayObject.$getRenderNode();
}
else {
node = displayObject.$renderNode;
}
}
displayObject.$cacheDirty = false;
if (node) {
drawCalls++;
buffer.$offsetX = offsetX;
buffer.$offsetY = offsetY;
switch (node.type) {
case sys.RenderNodeType.BitmapNode:
this.renderBitmap(<sys.BitmapNode>node, buffer);
break;
case sys.RenderNodeType.TextNode:
this.renderText(<sys.TextNode>node, buffer);
break;
case sys.RenderNodeType.GraphicsNode:
this.renderGraphics(<sys.GraphicsNode>node, buffer);
break;
case sys.RenderNodeType.GroupNode:
this.renderGroup(<sys.GroupNode>node, buffer);
break;
case sys.RenderNodeType.MeshNode:
this.renderMesh(<sys.MeshNode>node, buffer);
break;
case sys.RenderNodeType.NormalBitmapNode:
this.renderNormalBitmap(<sys.NormalBitmapNode>node, buffer);
break;
}
buffer.$offsetX = 0;
buffer.$offsetY = 0;
}
if (displayList && !isStage) {
return drawCalls;
}
let children = displayObject.$children;
if (children) {
let length = children.length;
for (let i = 0; i < length; i++) {
let child = children[i];
let offsetX2;
let offsetY2;
let tempAlpha;
if (child.$alpha != 1) {
tempAlpha = buffer.globalAlpha;
buffer.globalAlpha *= child.$alpha;
}
let savedMatrix: Matrix;
if (child.$useTranslate) {
let m = child.$getMatrix();
offsetX2 = offsetX + child.$x;
offsetY2 = offsetY + child.$y;
let m2 = buffer.globalMatrix;
savedMatrix = Matrix.create();
savedMatrix.a = m2.a;
savedMatrix.b = m2.b;
savedMatrix.c = m2.c;
savedMatrix.d = m2.d;
savedMatrix.tx = m2.tx;
savedMatrix.ty = m2.ty;
buffer.transform(m.a, m.b, m.c, m.d, offsetX2, offsetY2);
offsetX2 = -child.$anchorOffsetX;
offsetY2 = -child.$anchorOffsetY;
}
else {
offsetX2 = offsetX + child.$x - child.$anchorOffsetX;
offsetY2 = offsetY + child.$y - child.$anchorOffsetY;
}
switch (child.$renderMode) {
case RenderMode.NONE:
break;
case RenderMode.FILTER:
drawCalls += this.drawWithFilter(child, buffer, offsetX2, offsetY2);
break;
case RenderMode.CLIP:
drawCalls += this.drawWithClip(child, buffer, offsetX2, offsetY2);
break;
case RenderMode.SCROLLRECT:
drawCalls += this.drawWithScrollRect(child, buffer, offsetX2, offsetY2);
break;
default:
drawCalls += this.drawDisplayObject(child, buffer, offsetX2, offsetY2);
break;
}
if (tempAlpha) {
buffer.globalAlpha = tempAlpha;
}
if (savedMatrix) {
let m = buffer.globalMatrix;
m.a = savedMatrix.a;
m.b = savedMatrix.b;
m.c = savedMatrix.c;
m.d = savedMatrix.d;
m.tx = savedMatrix.tx;
m.ty = savedMatrix.ty;
Matrix.release(savedMatrix);
}
}
}
return drawCalls;
}
/**
* @private
*/
private drawWithFilter(displayObject: DisplayObject, buffer: WebGLRenderBuffer, offsetX: number, offsetY: number): number {
let drawCalls = 0;
if (displayObject.$children && displayObject.$children.length == 0 && (!displayObject.$renderNode || displayObject.$renderNode.$getRenderCount() == 0)) {
return;
}
let filters = displayObject.$filters;
let hasBlendMode = (displayObject.$blendMode !== 0);
let compositeOp: string;
if (hasBlendMode) {
compositeOp = blendModes[displayObject.$blendMode];
if (!compositeOp) {
compositeOp = defaultCompositeOp;
}
}
let displayBounds = displayObject.$getOriginalBounds();
if (displayBounds.width <= 0 || displayBounds.height <= 0) {
return drawCalls;
}
if (!displayObject.mask && filters.length == 1 && (filters[0].type == "colorTransform" || (filters[0].type === "custom" && (<CustomFilter>filters[0]).padding === 0))) {
let childrenDrawCount = this.getRenderCount(displayObject);
if (!displayObject.$children || childrenDrawCount == 1) {
if (hasBlendMode) {
buffer.context.setGlobalCompositeOperation(compositeOp);
}
buffer.context.$filter = <ColorMatrixFilter>filters[0];
if (displayObject.$mask) {
drawCalls += this.drawWithClip(displayObject, buffer, offsetX, offsetY);
}
else if (displayObject.$scrollRect || displayObject.$maskRect) {
drawCalls += this.drawWithScrollRect(displayObject, buffer, offsetX, offsetY);
}
else {
drawCalls += this.drawDisplayObject(displayObject, buffer, offsetX, offsetY);
}
buffer.context.$filter = null;
if (hasBlendMode) {
buffer.context.setGlobalCompositeOperation(defaultCompositeOp);
}
return drawCalls;
}
}
// 为显示对象创建一个新的buffer
let displayBuffer = this.createRenderBuffer(displayBounds.width, displayBounds.height);
displayBuffer.context.pushBuffer(displayBuffer);
//todo 可以优化减少draw次数
if (displayObject.$mask) {
drawCalls += this.drawWithClip(displayObject, displayBuffer, -displayBounds.x, -displayBounds.y);
}
else if (displayObject.$scrollRect || displayObject.$maskRect) {
drawCalls += this.drawWithScrollRect(displayObject, displayBuffer, -displayBounds.x, -displayBounds.y);
}
else {
drawCalls += this.drawDisplayObject(displayObject, displayBuffer, -displayBounds.x, -displayBounds.y);
}
displayBuffer.context.popBuffer();
//绘制结果到屏幕
if (drawCalls > 0) {
if (hasBlendMode) {
buffer.context.setGlobalCompositeOperation(compositeOp);
}
drawCalls++;
// 绘制结果的时候,应用滤镜
buffer.$offsetX = offsetX + displayBounds.x;
buffer.$offsetY = offsetY + displayBounds.y;
buffer.context.drawTargetWidthFilters(filters, displayBuffer);
if (hasBlendMode) {
buffer.context.setGlobalCompositeOperation(defaultCompositeOp);
}
}
renderBufferPool.push(displayBuffer);
return drawCalls;
}
private getRenderCount(displayObject: DisplayObject): number {
let childrenDrawCount = 0;
if (displayObject.$children) {
for (let child of displayObject.$children) {
let node = child.$getRenderNode();
if (node) {
childrenDrawCount += node.$getRenderCount();
}
if (child.$children) {
childrenDrawCount += this.getRenderCount(child);
}
}
}
return childrenDrawCount;
}
/**
* @private
*/
private drawWithClip(displayObject: DisplayObject, buffer: WebGLRenderBuffer, offsetX: number, offsetY: number): number {
let drawCalls = 0;
let hasBlendMode = (displayObject.$blendMode !== 0);
let compositeOp: string;
if (hasBlendMode) {
compositeOp = blendModes[displayObject.$blendMode];
if (!compositeOp) {
compositeOp = defaultCompositeOp;
}
}
let scrollRect = displayObject.$scrollRect ? displayObject.$scrollRect : displayObject.$maskRect;
let mask = displayObject.$mask;
if (mask) {
let maskRenderMatrix = mask.$getMatrix();
//遮罩scaleX或scaleY为0,放弃绘制
if ((maskRenderMatrix.a == 0 && maskRenderMatrix.b == 0) || (maskRenderMatrix.c == 0 && maskRenderMatrix.d == 0)) {
return drawCalls;
}
}
//没有遮罩,同时显示对象没有子项
if (!mask && (!displayObject.$children || displayObject.$children.length == 0)) {
if (scrollRect) {
buffer.context.pushMask(scrollRect.x + offsetX, scrollRect.y + offsetY, scrollRect.width, scrollRect.height);
}
//绘制显示对象
if (hasBlendMode) {
buffer.context.setGlobalCompositeOperation(compositeOp);
}
drawCalls += this.drawDisplayObject(displayObject, buffer, offsetX, offsetY);
if (hasBlendMode) {
buffer.context.setGlobalCompositeOperation(defaultCompositeOp);
}
if (scrollRect) {
buffer.context.popMask();
}
return drawCalls;
}
else {
let displayBounds = displayObject.$getOriginalBounds();
//绘制显示对象自身,若有scrollRect,应用clip
let displayBuffer = this.createRenderBuffer(displayBounds.width, displayBounds.height);
displayBuffer.context.pushBuffer(displayBuffer);
drawCalls += this.drawDisplayObject(displayObject, displayBuffer, -displayBounds.x, -displayBounds.y);
//绘制遮罩
if (mask) {
let maskBuffer = this.createRenderBuffer(displayBounds.width, displayBounds.height);
maskBuffer.context.pushBuffer(maskBuffer);
let maskMatrix = Matrix.create();
maskMatrix.copyFrom(mask.$getConcatenatedMatrix());
mask.$getConcatenatedMatrixAt(displayObject, maskMatrix);
maskBuffer.setTransform(maskMatrix.a, maskMatrix.b, maskMatrix.c, maskMatrix.d, maskMatrix.tx, maskMatrix.ty);
Matrix.release(maskMatrix);
drawCalls += this.drawDisplayObject(mask, maskBuffer, -displayBounds.x, -displayBounds.y);
maskBuffer.context.popBuffer();
displayBuffer.context.setGlobalCompositeOperation("destination-in");
displayBuffer.setTransform(1, 0, 0, -1, 0, maskBuffer.height);
displayBuffer.globalAlpha = 1;
let maskBufferWidth = maskBuffer.rootRenderTarget.width;
let maskBufferHeight = maskBuffer.rootRenderTarget.height;
displayBuffer.context.drawTexture(maskBuffer.rootRenderTarget.texture, 0, 0, maskBufferWidth, maskBufferHeight,
0, 0, maskBufferWidth, maskBufferHeight, maskBufferWidth, maskBufferHeight);
displayBuffer.setTransform(1, 0, 0, 1, 0, 0);
displayBuffer.context.setGlobalCompositeOperation("source-over");
renderBufferPool.push(maskBuffer);
}
displayBuffer.context.setGlobalCompositeOperation(defaultCompositeOp);
displayBuffer.context.popBuffer();
//绘制结果到屏幕
if (drawCalls > 0) {
drawCalls++;
if (hasBlendMode) {
buffer.context.setGlobalCompositeOperation(compositeOp);
}
if (scrollRect) {
buffer.context.pushMask(scrollRect.x + offsetX, scrollRect.y + offsetY, scrollRect.width, scrollRect.height);
}
buffer.globalAlpha = 1;
let savedMatrix = Matrix.create();
let curMatrix = buffer.globalMatrix;
savedMatrix.a = curMatrix.a;
savedMatrix.b = curMatrix.b;
savedMatrix.c = curMatrix.c;
savedMatrix.d = curMatrix.d;
savedMatrix.tx = curMatrix.tx;
savedMatrix.ty = curMatrix.ty;
buffer.setTransform(egret.sys.DisplayList.$canvasScaleX, 0, 0, -egret.sys.DisplayList.$canvasScaleY, (offsetX + displayBounds.x) * egret.sys.DisplayList.$canvasScaleX, (offsetY + displayBounds.y + displayBuffer.height) * egret.sys.DisplayList.$canvasScaleY);
let displayBufferWidth = displayBuffer.rootRenderTarget.width;
let displayBufferHeight = displayBuffer.rootRenderTarget.height;
buffer.context.drawTexture(displayBuffer.rootRenderTarget.texture, 0, 0, displayBufferWidth, displayBufferHeight,
0, 0, displayBufferWidth, displayBufferHeight, displayBufferWidth, displayBufferHeight);
if (scrollRect) {
displayBuffer.context.popMask();
}
if (hasBlendMode) {
buffer.context.setGlobalCompositeOperation(defaultCompositeOp);
}
let matrix = buffer.globalMatrix;
matrix.a = savedMatrix.a;
matrix.b = savedMatrix.b;
matrix.c = savedMatrix.c;
matrix.d = savedMatrix.d;
matrix.tx = savedMatrix.tx;
matrix.ty = savedMatrix.ty;
Matrix.release(savedMatrix);
}
renderBufferPool.push(displayBuffer);
return drawCalls;
}
}
/**
* @private
*/
private drawWithScrollRect(displayObject: DisplayObject, buffer: WebGLRenderBuffer, offsetX: number, offsetY: number): number {
let drawCalls = 0;
let scrollRect = displayObject.$scrollRect ? displayObject.$scrollRect : displayObject.$maskRect;
if (scrollRect.isEmpty()) {
return drawCalls;
}
if (displayObject.$scrollRect) {
offsetX -= scrollRect.x;
offsetY -= scrollRect.y;
}
let m = buffer.globalMatrix;
let context = buffer.context;
let scissor = false;
if (buffer.$hasScissor || m.b != 0 || m.c != 0) {// 有旋转的情况下不能使用scissor
buffer.context.pushMask(scrollRect.x + offsetX, scrollRect.y + offsetY, scrollRect.width, scrollRect.height);
} else {
let a = m.a;
let d = m.d;
let tx = m.tx;
let ty = m.ty;
let x = scrollRect.x + offsetX;
let y = scrollRect.y + offsetY;
let xMax = x + scrollRect.width;
let yMax = y + scrollRect.height;
let minX: number, minY: number, maxX: number, maxY: number;
//优化,通常情况下不缩放的对象占多数,直接加上偏移量即可。
if (a == 1.0 && d == 1.0) {
minX = x + tx;
minY = y + ty;
maxX = xMax + tx;
maxY = yMax + ty;
}
else {
let x0 = a * x + tx;
let y0 = d * y + ty;
let x1 = a * xMax + tx;
let y1 = d * y + ty;
let x2 = a * xMax + tx;
let y2 = d * yMax + ty;
let x3 = a * x + tx;
let y3 = d * yMax + ty;
let tmp = 0;
if (x0 > x1) {
tmp = x0;
x0 = x1;
x1 = tmp;
}
if (x2 > x3) {
tmp = x2;
x2 = x3;
x3 = tmp;
}
minX = (x0 < x2 ? x0 : x2);
maxX = (x1 > x3 ? x1 : x3);
if (y0 > y1) {
tmp = y0;
y0 = y1;
y1 = tmp;
}
if (y2 > y3) {
tmp = y2;
y2 = y3;
y3 = tmp;
}
minY = (y0 < y2 ? y0 : y2);
maxY = (y1 > y3 ? y1 : y3);
}
context.enableScissor(minX, -maxY + buffer.height, maxX - minX, maxY - minY);
scissor = true;
}
drawCalls += this.drawDisplayObject(displayObject, buffer, offsetX, offsetY);
if (scissor) {
context.disableScissor();
} else {
context.popMask();
}
return drawCalls;
}
/**
* 将一个RenderNode对象绘制到渲染缓冲
* @param node 要绘制的节点
* @param buffer 渲染缓冲
* @param matrix 要叠加的矩阵
* @param forHitTest 绘制结果是用于碰撞检测。若为true,当渲染GraphicsNode时,会忽略透明度样式设置,全都绘制为不透明的。
*/
public drawNodeToBuffer(node: sys.RenderNode, buffer: WebGLRenderBuffer, matrix: Matrix, forHitTest?: boolean): void {
let webglBuffer: WebGLRenderBuffer = <WebGLRenderBuffer>buffer;
//pushRenderTARGET
webglBuffer.context.pushBuffer(webglBuffer);
webglBuffer.setTransform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty);
this.renderNode(node, buffer, 0, 0, forHitTest);
webglBuffer.context.$drawWebGL();
webglBuffer.onRenderFinish();
//popRenderTARGET
webglBuffer.context.popBuffer();
}
/**
* 将一个DisplayObject绘制到渲染缓冲,用于RenderTexture绘制
* @param displayObject 要绘制的显示对象
* @param buffer 渲染缓冲
* @param matrix 要叠加的矩阵
*/
public drawDisplayToBuffer(displayObject: DisplayObject, buffer: WebGLRenderBuffer, matrix: Matrix): number {
buffer.context.pushBuffer(buffer);
if (matrix) {
buffer.setTransform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty);
}
let node: sys.RenderNode;
if (displayObject.$renderDirty) {
node = displayObject.$getRenderNode();
}
else {
node = displayObject.$renderNode;
}
let drawCalls = 0;
if (node) {
drawCalls++;
switch (node.type) {
case sys.RenderNodeType.BitmapNode:
this.renderBitmap(<sys.BitmapNode>node, buffer);
break;
case sys.RenderNodeType.TextNode:
this.renderText(<sys.TextNode>node, buffer);
break;
case sys.RenderNodeType.GraphicsNode:
this.renderGraphics(<sys.GraphicsNode>node, buffer);
break;
case sys.RenderNodeType.GroupNode:
this.renderGroup(<sys.GroupNode>node, buffer);
break;
case sys.RenderNodeType.MeshNode:
this.renderMesh(<sys.MeshNode>node, buffer);
break;
case sys.RenderNodeType.NormalBitmapNode:
this.renderNormalBitmap(<sys.NormalBitmapNode>node, buffer);
break;
}
}
let children = displayObject.$children;
if (children) {
let length = children.length;
for (let i = 0; i < length; i++) {
let child = children[i];
switch (child.$renderMode) {
case RenderMode.NONE:
break;
case RenderMode.FILTER:
drawCalls += this.drawWithFilter(child, buffer, 0, 0);
break;
case RenderMode.CLIP:
drawCalls += this.drawWithClip(child, buffer, 0, 0);
break;
case RenderMode.SCROLLRECT:
drawCalls += this.drawWithScrollRect(child, buffer, 0, 0);
break;
default:
drawCalls += this.drawDisplayObject(child, buffer, 0, 0);
break;
}
}
}
buffer.context.$drawWebGL();
buffer.onRenderFinish();
buffer.context.popBuffer();
return drawCalls;
}
/**
* @private
*/
private renderNode(node: sys.RenderNode, buffer: WebGLRenderBuffer, offsetX: number, offsetY: number, forHitTest?: boolean): void {
buffer.$offsetX = offsetX;
buffer.$offsetY = offsetY;
switch (node.type) {
case sys.RenderNodeType.BitmapNode:
this.renderBitmap(<sys.BitmapNode>node, buffer);
break;
case sys.RenderNodeType.TextNode:
this.renderText(<sys.TextNode>node, buffer);
break;
case sys.RenderNodeType.GraphicsNode:
this.renderGraphics(<sys.GraphicsNode>node, buffer, forHitTest);
break;
case sys.RenderNodeType.GroupNode:
this.renderGroup(<sys.GroupNode>node, buffer);
break;
case sys.RenderNodeType.MeshNode:
this.renderMesh(<sys.MeshNode>node, buffer);
break;
case sys.RenderNodeType.NormalBitmapNode:
this.renderNormalBitmap(<sys.NormalBitmapNode>node, buffer);
break;
}
}
/**
* @private
*/
private renderNormalBitmap(node: sys.NormalBitmapNode, buffer: WebGLRenderBuffer): void {
let image = node.image;
if (!image) {
return;
}
buffer.context.drawImage(image, node.sourceX, node.sourceY, node.sourceW, node.sourceH,
node.drawX, node.drawY, node.drawW, node.drawH, node.imageWidth, node.imageHeight, node.rotated, node.smoothing);
}
/**
* @private
*/
private renderBitmap(node: sys.BitmapNode, buffer: WebGLRenderBuffer): void {
let image = node.image;
if (!image) {
return;
}
//buffer.imageSmoothingEnabled = node.smoothing;
let data = node.drawData;
let length = data.length;
let pos = 0;
let m = node.matrix;
let blendMode = node.blendMode;
let alpha = node.alpha;
let savedMatrix;
let offsetX;
let offsetY;
if (m) {
savedMatrix = Matrix.create();
let curMatrix = buffer.globalMatrix;
savedMatrix.a = curMatrix.a;
savedMatrix.b = curMatrix.b;
savedMatrix.c = curMatrix.c;
savedMatrix.d = curMatrix.d;
savedMatrix.tx = curMatrix.tx;
savedMatrix.ty = curMatrix.ty;
offsetX = buffer.$offsetX;
offsetY = buffer.$offsetY;
buffer.useOffset();
buffer.transform(m.a, m.b, m.c, m.d, m.tx, m.ty);
}
//这里不考虑嵌套
if (blendMode) {
buffer.context.setGlobalCompositeOperation(blendModes[blendMode]);
}
let originAlpha: number;
if (alpha == alpha) {
originAlpha = buffer.globalAlpha;
buffer.globalAlpha *= alpha;
}
if (node.filter) {
buffer.context.$filter = node.filter;
while (pos < length) {
buffer.context.drawImage(image, data[pos++], data[pos++], data[pos++], data[pos++],
data[pos++], data[pos++], data[pos++], data[pos++], node.imageWidth, node.imageHeight, node.rotated, node.smoothing);
}
buffer.context.$filter = null;
}
else {
while (pos < length) {
buffer.context.drawImage(image, data[pos++], data[pos++], data[pos++], data[pos++],
data[pos++], data[pos++], data[pos++], data[pos++], node.imageWidth, node.imageHeight, node.rotated, node.smoothing);
}
}
if (blendMode) {
buffer.context.setGlobalCompositeOperation(defaultCompositeOp);
}
if (alpha == alpha) {
buffer.globalAlpha = originAlpha;
}
if (m) {
let matrix = buffer.globalMatrix;
matrix.a = savedMatrix.a;
matrix.b = savedMatrix.b;
matrix.c = savedMatrix.c;
matrix.d = savedMatrix.d;
matrix.tx = savedMatrix.tx;
matrix.ty = savedMatrix.ty;
buffer.$offsetX = offsetX;
buffer.$offsetY = offsetY;
Matrix.release(savedMatrix);
}
}
/**
* @private
*/
private renderMesh(node: sys.MeshNode, buffer: WebGLRenderBuffer): void {
let image = node.image;
//buffer.imageSmoothingEnabled = node.smoothing;
let data = node.drawData;
let length = data.length;
let pos = 0;
let m = node.matrix;
let blendMode = node.blendMode;
let alpha = node.alpha;
let savedMatrix;
let offsetX;
let offsetY;
if (m) {
savedMatrix = Matrix.create();
let curMatrix = buffer.globalMatrix;
savedMatrix.a = curMatrix.a;
savedMatrix.b = curMatrix.b;
savedMatrix.c = curMatrix.c;
savedMatrix.d = curMatrix.d;
savedMatrix.tx = curMatrix.tx;
savedMatrix.ty = curMatrix.ty;
offsetX = buffer.$offsetX;
offsetY = buffer.$offsetY;
buffer.useOffset();
buffer.transform(m.a, m.b, m.c, m.d, m.tx, m.ty);
}
//这里不考虑嵌套
if (blendMode) {
buffer.context.setGlobalCompositeOperation(blendModes[blendMode]);
}
let originAlpha: number;
if (alpha == alpha) {
originAlpha = buffer.globalAlpha;
buffer.globalAlpha *= alpha;
}
if (node.filter) {
buffer.context.$filter = node.filter;
while (pos < length) {
buffer.context.drawMesh(image, data[pos++], data[pos++], data[pos++], data[pos++],
data[pos++], data[pos++], data[pos++], data[pos++], node.imageWidth, node.imageHeight, node.uvs, node.vertices, node.indices, node.bounds, node.rotated, node.smoothing);
}
buffer.context.$filter = null;
}
else {
while (pos < length) {
buffer.context.drawMesh(image, data[pos++], data[pos++], data[pos++], data[pos++],
data[pos++], data[pos++], data[pos++], data[pos++], node.imageWidth, node.imageHeight, node.uvs, node.vertices, node.indices, node.bounds, node.rotated, node.smoothing);
}
}
if (blendMode) {
buffer.context.setGlobalCompositeOperation(defaultCompositeOp);
}
if (alpha == alpha) {
buffer.globalAlpha = originAlpha;
}
if (m) {
let matrix = buffer.globalMatrix;
matrix.a = savedMatrix.a;
matrix.b = savedMatrix.b;
matrix.c = savedMatrix.c;
matrix.d = savedMatrix.d;
matrix.tx = savedMatrix.tx;
matrix.ty = savedMatrix.ty;
buffer.$offsetX = offsetX;
buffer.$offsetY = offsetY;
Matrix.release(savedMatrix);
}
}
private canvasRenderer: CanvasRenderer;
private canvasRenderBuffer: CanvasRenderBuffer;
/**
* @private
*/
private renderText(node: sys.TextNode, buffer: WebGLRenderBuffer): void {
let width = node.width - node.x;
let height = node.height - node.y;
if (width <= 0 || height <= 0 || !width || !height || node.drawData.length == 0) {
return;
}
let canvasScaleX = sys.DisplayList.$canvasScaleX;
let canvasScaleY = sys.DisplayList.$canvasScaleY;
let maxTextureSize = buffer.context.$maxTextureSize;
if (width * canvasScaleX > maxTextureSize) {
canvasScaleX *= maxTextureSize / (width * canvasScaleX);
}
if (height * canvasScaleY > maxTextureSize) {
canvasScaleY *= maxTextureSize / (height * canvasScaleY);
}
width *= canvasScaleX;
height *= canvasScaleY;
let x = node.x * canvasScaleX;
let y = node.y * canvasScaleY;
if (node.$canvasScaleX != canvasScaleX || node.$canvasScaleY != canvasScaleY) {
node.$canvasScaleX = canvasScaleX;
node.$canvasScaleY = canvasScaleY;
node.dirtyRender = true;
}
if (!this.canvasRenderBuffer || !this.canvasRenderBuffer.context) {
this.canvasRenderer = new CanvasRenderer();
this.canvasRenderBuffer = new CanvasRenderBuffer(width, height);
}
else if (node.dirtyRender) {
this.canvasRenderBuffer.resize(width, height);
}
if (!this.canvasRenderBuffer.context) {
return;
}
if (canvasScaleX != 1 || canvasScaleY != 1) {
this.canvasRenderBuffer.context.setTransform(canvasScaleX, 0, 0, canvasScaleY, 0, 0);
}
if (x || y) {
if (node.dirtyRender) {
this.canvasRenderBuffer.context.setTransform(canvasScaleX, 0, 0, canvasScaleY, -x, -y);
}
buffer.transform(1, 0, 0, 1, x / canvasScaleX, y / canvasScaleY);
}
else if (canvasScaleX != 1 || canvasScaleY != 1) {
this.canvasRenderBuffer.context.setTransform(canvasScaleX, 0, 0, canvasScaleY, 0, 0);
}
if (node.dirtyRender) {
let surface = this.canvasRenderBuffer.surface;
this.canvasRenderer.renderText(node, this.canvasRenderBuffer.context);
// 拷贝canvas到texture
let texture = node.$texture;
if (!texture) {
texture = buffer.context.createTexture(<BitmapData><any>surface);
node.$texture = texture;
} else {
// 重新拷贝新的图像
buffer.context.updateTexture(texture, <BitmapData><any>surface);
}
// 保存材质尺寸
node.$textureWidth = surface.width;
node.$textureHeight = surface.height;
}
let textureWidth = node.$textureWidth;
let textureHeight = node.$textureHeight;
buffer.context.drawTexture(node.$texture, 0, 0, textureWidth, textureHeight, 0, 0, textureWidth / canvasScaleX, textureHeight / canvasScaleY, textureWidth, textureHeight);
if (x || y) {
if (node.dirtyRender) {
this.canvasRenderBuffer.context.setTransform(canvasScaleX, 0, 0, canvasScaleY, 0, 0);
}
buffer.transform(1, 0, 0, 1, -x / canvasScaleX, -y / canvasScaleY);
}
node.dirtyRender = false;
}
/**
* @private
*/
private renderGraphics(node: sys.GraphicsNode, buffer: WebGLRenderBuffer, forHitTest?: boolean): void {
let width = node.width;
let height = node.height;
if (width <= 0 || height <= 0 || !width || !height || node.drawData.length == 0) {
return;
}
let canvasScaleX = sys.DisplayList.$canvasScaleX;
let canvasScaleY = sys.DisplayList.$canvasScaleY;
if (width * canvasScaleX < 1 || height * canvasScaleY < 1) {
canvasScaleX = canvasScaleY = 1;
}
if (node.$canvasScaleX != canvasScaleX || node.$canvasScaleY != canvasScaleY) {
node.$canvasScaleX = canvasScaleX;
node.$canvasScaleY = canvasScaleY;
node.dirtyRender = true;
}
//缩放叠加 width2 / width 填满整个区域
width = width * canvasScaleX;
height = height * canvasScaleY;
var width2 = Math.ceil(width);
var height2 = Math.ceil(height);
canvasScaleX *= width2 / width;
canvasScaleY *= height2 / height;
width = width2;
height = height2;
if (!this.canvasRenderBuffer || !this.canvasRenderBuffer.context) {
this.canvasRenderer = new CanvasRenderer();
this.canvasRenderBuffer = new CanvasRenderBuffer(width, height);
}
else if (node.dirtyRender || forHitTest) {
this.canvasRenderBuffer.resize(width, height);
}
if (!this.canvasRenderBuffer.context) {
return;
}
if (canvasScaleX != 1 || canvasScaleY != 1) {
this.canvasRenderBuffer.context.setTransform(canvasScaleX, 0, 0, canvasScaleY, 0, 0);
}
if (node.x || node.y) {
if (node.dirtyRender || forHitTest) {
this.canvasRenderBuffer.context.translate(-node.x, -node.y);
}
buffer.transform(1, 0, 0, 1, node.x, node.y);
}
let surface = this.canvasRenderBuffer.surface;
if (forHitTest) {
this.canvasRenderer.renderGraphics(node, this.canvasRenderBuffer.context, true);
WebGLUtils.deleteWebGLTexture(surface);
let texture = buffer.context.getWebGLTexture(<BitmapData><any>surface);
buffer.context.drawTexture(texture, 0, 0, width, height, 0, 0, width, height, surface.width, surface.height);
} else {
if (node.dirtyRender) {
this.canvasRenderer.renderGraphics(node, this.canvasRenderBuffer.context);
// 拷贝canvas到texture
let texture: WebGLTexture = node.$texture;
if (!texture) {
texture = buffer.context.createTexture(<BitmapData><any>surface);
node.$texture = texture;
} else {
// 重新拷贝新的图像
buffer.context.updateTexture(texture, <BitmapData><any>surface);
}
// 保存材质尺寸
node.$textureWidth = surface.width;
node.$textureHeight = surface.height;
}
let textureWidth = node.$textureWidth;
let textureHeight = node.$textureHeight;
buffer.context.drawTexture(node.$texture, 0, 0, textureWidth, textureHeight, 0, 0, textureWidth / canvasScaleX, textureHeight / canvasScaleY, textureWidth, textureHeight);
}
if (node.x || node.y) {
if (node.dirtyRender || forHitTest) {
this.canvasRenderBuffer.context.translate(node.x, node.y);
}
buffer.transform(1, 0, 0, 1, -node.x, -node.y);
}
if (!forHitTest) {
node.dirtyRender = false;
}
}
private renderGroup(groupNode: sys.GroupNode, buffer: WebGLRenderBuffer): void {
let m = groupNode.matrix;
let savedMatrix;
let offsetX;
let offsetY;
if (m) {
savedMatrix = Matrix.create();
let curMatrix = buffer.globalMatrix;
savedMatrix.a = curMatrix.a;
savedMatrix.b = curMatrix.b;
savedMatrix.c = curMatrix.c;
savedMatrix.d = curMatrix.d;
savedMatrix.tx = curMatrix.tx;
savedMatrix.ty = curMatrix.ty;
offsetX = buffer.$offsetX;
offsetY = buffer.$offsetY;
buffer.useOffset();
buffer.transform(m.a, m.b, m.c, m.d, m.tx, m.ty);
}
let children = groupNode.drawData;
let length = children.length;
for (let i = 0; i < length; i++) {
let node: sys.RenderNode = children[i];
this.renderNode(node, buffer, buffer.$offsetX, buffer.$offsetY);
}
if (m) {
let matrix = buffer.globalMatrix;
matrix.a = savedMatrix.a;
matrix.b = savedMatrix.b;
matrix.c = savedMatrix.c;
matrix.d = savedMatrix.d;
matrix.tx = savedMatrix.tx;
matrix.ty = savedMatrix.ty;
buffer.$offsetX = offsetX;
buffer.$offsetY = offsetY;
Matrix.release(savedMatrix);
}
}
/**
* @private
*/
private createRenderBuffer(width: number, height: number): WebGLRenderBuffer {
let buffer = renderBufferPool.pop();
if (buffer) {
buffer.resize(width, height);
}
else {
buffer = new WebGLRenderBuffer(width, height);
buffer.$computeDrawCall = false;
}
return buffer;
}
}
}