phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
433 lines (368 loc) • 13.7 kB
JavaScript
/**
* @author Richard Davey <rich@phaser.io>
* @copyright 2013-2026 Phaser Studio Inc.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var Commands = require('./Commands');
var GetCalcMatrix = require('../GetCalcMatrix');
var Utils = require('../../renderer/webgl/Utils');
var TransformMatrix = require('../components/TransformMatrix');
var Point = function (x, y, width)
{
this.x = x;
this.y = y;
this.width = width;
};
var Path = function (x, y, width)
{
this.points = [];
this.points[0] = new Point(x, y, width);
this.addPoint = function (x, y, width)
{
var point = this.points[this.points.length - 1];
if (point.x === x && point.y === y)
{
return;
}
this.points.push(new Point(x, y, width));
};
};
var matrixStack = [];
var tempMatrix = new TransformMatrix();
var renderMatrix = new TransformMatrix();
var fillTint = { TL: 0, TR: 0, BL: 0, BR: 0 };
var strokeTint = { TL: 0, TR: 0, BL: 0, BR: 0 };
var trianglePath = [
{ x: 0, y: 0, width: 0 },
{ x: 0, y: 0, width: 0 },
{ x: 0, y: 0, width: 0 },
{ x: 0, y: 0, width: 0 }
];
/**
* Renders this Game Object with the WebGL Renderer to the given Camera.
* The object will not render if any of its renderFlags are set or it is being actively filtered out by the Camera.
* This method should not be called directly. It is a utility function of the Render module.
*
* @method Phaser.GameObjects.Graphics#renderWebGL
* @since 3.0.0
* @private
*
* @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - A reference to the current active WebGL renderer.
* @param {Phaser.GameObjects.Graphics} src - The Game Object being rendered in this call.
* @param {Phaser.Renderer.WebGL.DrawingContext} drawingContext - The current drawing context.
* @param {Phaser.GameObjects.Components.TransformMatrix} parentMatrix - This transform matrix is defined if the game object is nested
*/
var GraphicsWebGLRenderer = function (renderer, src, drawingContext, parentMatrix)
{
if (src.commandBuffer.length === 0)
{
return;
}
var customRenderNodes = src.customRenderNodes;
var defaultRenderNodes = src.defaultRenderNodes;
var submitterNode = customRenderNodes.Submitter || defaultRenderNodes.Submitter;
var lighting = src.lighting;
var currentContext = drawingContext;
var camera = currentContext.camera;
camera.addToRenderList(src);
var calcMatrix = GetCalcMatrix(src, camera, parentMatrix, !drawingContext.useCanvas).calc;
var currentMatrix = tempMatrix.loadIdentity();
var commands = src.commandBuffer;
var alpha = src.alpha;
var pathDetailThreshold = Math.max(
src.pathDetailThreshold,
renderer.config.pathDetailThreshold,
0
);
var lineWidth = 1;
var tx = 0;
var ty = 0;
var ta = 0;
var iterStep = 0.01;
var PI2 = Math.PI * 2;
var cmd;
var path = [];
var pathIndex = 0;
var pathOpen = true;
var lastPath = null;
var getTint = Utils.getTintAppendFloatAlpha;
for (var cmdIndex = 0; cmdIndex < commands.length; cmdIndex++)
{
cmd = commands[cmdIndex];
switch (cmd)
{
case Commands.BEGIN_PATH:
{
path.length = 0;
lastPath = null;
pathOpen = true;
break;
}
case Commands.CLOSE_PATH:
{
pathOpen = false;
if (lastPath && lastPath.points.length)
{
lastPath.points.push(lastPath.points[0]);
}
break;
}
case Commands.FILL_PATH:
{
calcMatrix.multiply(currentMatrix, renderMatrix);
for (pathIndex = 0; pathIndex < path.length; pathIndex++)
{
(customRenderNodes.FillPath || defaultRenderNodes.FillPath).run(
currentContext,
renderMatrix,
submitterNode,
path[pathIndex].points,
fillTint.TL,
fillTint.TR,
fillTint.BL,
pathDetailThreshold,
lighting
);
}
break;
}
case Commands.STROKE_PATH:
{
calcMatrix.multiply(currentMatrix, renderMatrix);
for (pathIndex = 0; pathIndex < path.length; pathIndex++)
{
(customRenderNodes.StrokePath || defaultRenderNodes.StrokePath).run(
currentContext,
submitterNode,
path[pathIndex].points,
lineWidth,
pathOpen,
renderMatrix,
strokeTint.TL,
strokeTint.TR,
strokeTint.BL,
strokeTint.BR,
pathDetailThreshold,
lighting
);
}
break;
}
case Commands.LINE_STYLE:
{
lineWidth = commands[++cmdIndex];
var strokeColor = commands[++cmdIndex];
var strokeAlpha = commands[++cmdIndex] * alpha;
var strokeTintColor = getTint(strokeColor, strokeAlpha);
strokeTint.TL = strokeTintColor;
strokeTint.TR = strokeTintColor;
strokeTint.BL = strokeTintColor;
strokeTint.BR = strokeTintColor;
break;
}
case Commands.FILL_STYLE:
{
var fillColor = commands[++cmdIndex];
var fillAlpha = commands[++cmdIndex] * alpha;
var fillTintColor = getTint(fillColor, fillAlpha);
fillTint.TL = fillTintColor;
fillTint.TR = fillTintColor;
fillTint.BL = fillTintColor;
fillTint.BR = fillTintColor;
break;
}
case Commands.GRADIENT_FILL_STYLE:
{
var alphaTL = commands[++cmdIndex] * alpha;
var alphaTR = commands[++cmdIndex] * alpha;
var alphaBL = commands[++cmdIndex] * alpha;
var alphaBR = commands[++cmdIndex] * alpha;
fillTint.TL = getTint(commands[++cmdIndex], alphaTL);
fillTint.TR = getTint(commands[++cmdIndex], alphaTR);
fillTint.BL = getTint(commands[++cmdIndex], alphaBL);
fillTint.BR = getTint(commands[++cmdIndex], alphaBR);
break;
}
case Commands.GRADIENT_LINE_STYLE:
{
lineWidth = commands[++cmdIndex];
var gradientLineAlpha = commands[++cmdIndex] * alpha;
strokeTint.TL = getTint(commands[++cmdIndex], gradientLineAlpha);
strokeTint.TR = getTint(commands[++cmdIndex], gradientLineAlpha);
strokeTint.BL = getTint(commands[++cmdIndex], gradientLineAlpha);
strokeTint.BR = getTint(commands[++cmdIndex], gradientLineAlpha);
break;
}
case Commands.ARC:
{
var iteration = 0;
var x = commands[++cmdIndex];
var y = commands[++cmdIndex];
var radius = commands[++cmdIndex];
var startAngle = commands[++cmdIndex];
var endAngle = commands[++cmdIndex];
var anticlockwise = commands[++cmdIndex];
var overshoot = commands[++cmdIndex];
endAngle -= startAngle;
if (anticlockwise)
{
if (endAngle < -PI2)
{
endAngle = -PI2;
}
else if (endAngle > 0)
{
endAngle = -PI2 + endAngle % PI2;
}
}
else if (endAngle > PI2)
{
endAngle = PI2;
}
else if (endAngle < 0)
{
endAngle = PI2 + endAngle % PI2;
}
if (lastPath === null)
{
lastPath = new Path(x + Math.cos(startAngle) * radius, y + Math.sin(startAngle) * radius, lineWidth);
path.push(lastPath);
iteration += iterStep;
}
while (iteration < 1 + overshoot)
{
ta = endAngle * iteration + startAngle;
tx = x + Math.cos(ta) * radius;
ty = y + Math.sin(ta) * radius;
lastPath.addPoint(tx, ty, lineWidth);
iteration += iterStep;
}
ta = endAngle + startAngle;
tx = x + Math.cos(ta) * radius;
ty = y + Math.sin(ta) * radius;
lastPath.addPoint(tx, ty, lineWidth);
break;
}
case Commands.FILL_RECT:
{
calcMatrix.multiply(currentMatrix, renderMatrix);
(customRenderNodes.FillRect || defaultRenderNodes.FillRect).run(
currentContext,
renderMatrix,
submitterNode,
commands[++cmdIndex],
commands[++cmdIndex],
commands[++cmdIndex],
commands[++cmdIndex],
fillTint.TL,
fillTint.TR,
fillTint.BL,
fillTint.BR,
lighting
);
break;
}
case Commands.FILL_TRIANGLE:
{
calcMatrix.multiply(currentMatrix, renderMatrix);
(customRenderNodes.FillTri || defaultRenderNodes.FillTri).run(
currentContext,
renderMatrix,
submitterNode,
commands[++cmdIndex],
commands[++cmdIndex],
commands[++cmdIndex],
commands[++cmdIndex],
commands[++cmdIndex],
commands[++cmdIndex],
fillTint.TL,
fillTint.TR,
fillTint.BL,
lighting
);
break;
}
case Commands.STROKE_TRIANGLE:
{
calcMatrix.multiply(currentMatrix, renderMatrix);
trianglePath[0].x = commands[++cmdIndex];
trianglePath[0].y = commands[++cmdIndex];
trianglePath[0].width = lineWidth;
trianglePath[1].x = commands[++cmdIndex];
trianglePath[1].y = commands[++cmdIndex];
trianglePath[1].width = lineWidth;
trianglePath[2].x = commands[++cmdIndex];
trianglePath[2].y = commands[++cmdIndex];
trianglePath[2].width = lineWidth;
trianglePath[3].x = trianglePath[0].x;
trianglePath[3].y = trianglePath[0].y;
trianglePath[3].width = lineWidth;
(customRenderNodes.StrokePath || defaultRenderNodes.StrokePath).run(
currentContext,
submitterNode,
trianglePath,
lineWidth,
false,
renderMatrix,
strokeTint.TL,
strokeTint.TR,
strokeTint.BL,
strokeTint.BR,
lighting
);
break;
}
case Commands.LINE_TO:
{
x = commands[++cmdIndex];
y = commands[++cmdIndex];
if (lastPath !== null)
{
lastPath.addPoint(x, y, lineWidth);
}
else
{
lastPath = new Path(x, y, lineWidth);
path.push(lastPath);
}
break;
}
case Commands.MOVE_TO:
{
lastPath = new Path(commands[++cmdIndex], commands[++cmdIndex], lineWidth);
path.push(lastPath);
break;
}
case Commands.SAVE:
{
matrixStack.push(currentMatrix.copyToArray());
break;
}
case Commands.RESTORE:
{
currentMatrix.copyFromArray(matrixStack.pop());
break;
}
case Commands.TRANSLATE:
{
x = commands[++cmdIndex];
y = commands[++cmdIndex];
currentMatrix.translate(x, y);
break;
}
case Commands.SCALE:
{
x = commands[++cmdIndex];
y = commands[++cmdIndex];
currentMatrix.scale(x, y);
break;
}
case Commands.ROTATE:
{
currentMatrix.rotate(commands[++cmdIndex]);
break;
}
}
}
};
module.exports = GraphicsWebGLRenderer;