phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
416 lines (358 loc) • 14 kB
JavaScript
var SubmitterTileSprite = require('../../../../../src/renderer/webgl/renderNodes/submitter/SubmitterTileSprite');
describe('SubmitterTileSprite', function ()
{
var mockManager;
beforeEach(function ()
{
mockManager = {
renderer: {
normalTexture: {}
}
};
});
describe('constructor', function ()
{
it('should create an instance with default config name', function ()
{
var node = new SubmitterTileSprite(mockManager);
expect(node.name).toBe('SubmitterTileSprite');
});
it('should set the default batchHandler', function ()
{
var node = new SubmitterTileSprite(mockManager);
expect(node.batchHandler).toBe('BatchHandler');
});
it('should store the manager reference', function ()
{
var node = new SubmitterTileSprite(mockManager);
expect(node.manager).toBe(mockManager);
});
it('should set wrapFrame to true on _renderOptions', function ()
{
var node = new SubmitterTileSprite(mockManager);
expect(node._renderOptions.wrapFrame).toBe(true);
});
it('should allow a custom name via config', function ()
{
var node = new SubmitterTileSprite(mockManager, { name: 'MyTileSubmitter' });
expect(node.name).toBe('MyTileSubmitter');
});
it('should allow a custom batchHandler via config', function ()
{
var node = new SubmitterTileSprite(mockManager, { batchHandler: 'CustomBatch' });
expect(node.batchHandler).toBe('CustomBatch');
});
it('should initialise _renderOptions with multiTexturing true', function ()
{
var node = new SubmitterTileSprite(mockManager);
expect(node._renderOptions.multiTexturing).toBe(true);
});
it('should initialise _lightingOptions with normalMapRotation 0', function ()
{
var node = new SubmitterTileSprite(mockManager);
expect(node._lightingOptions.normalMapRotation).toBe(0);
});
});
describe('defaultConfig', function ()
{
it('should have the correct default name', function ()
{
expect(SubmitterTileSprite.prototype.defaultConfig.name).toBe('SubmitterTileSprite');
});
it('should have role set to Submitter', function ()
{
expect(SubmitterTileSprite.prototype.defaultConfig.role).toBe('Submitter');
});
it('should have batchHandler set to BatchHandler', function ()
{
expect(SubmitterTileSprite.prototype.defaultConfig.batchHandler).toBe('BatchHandler');
});
});
describe('run', function ()
{
var node;
var mockDrawingContext;
var mockGameObject;
var mockParentMatrix;
var mockTexturerNode;
var mockTransformerNode;
var mockBatchHandler;
beforeEach(function ()
{
node = new SubmitterTileSprite(mockManager);
mockDrawingContext = {};
mockBatchHandler = {
batch: vi.fn()
};
mockGameObject = {
tintMode: 0,
tintTopLeft: 0xffffff,
tintBottomLeft: 0xffffff,
tintTopRight: 0xffffff,
tintBottomRight: 0xffffff,
_alphaTL: 1,
_alphaBL: 1,
_alphaTR: 1,
_alphaBR: 1,
tileRotation: 0,
lighting: null,
displayTexture: null,
texture: {
smoothPixelArt: false,
dataSource: [ null ]
},
frame: {
sourceIndex: 0
},
customRenderNodes: {},
defaultRenderNodes: {
'BatchHandler': mockBatchHandler
}
};
mockTexturerNode = {
frame: {
source: {
glTexture: {}
},
u0: 0,
v0: 0,
u1: 1,
v1: 1
},
uvMatrix: {
quad: new Float32Array([ 0, 0, 0, 1, 1, 1, 1, 0 ])
}
};
mockTransformerNode = {
quad: new Float32Array([ 0, 0, 0, 100, 100, 100, 100, 0 ])
};
});
it('should call batch on the default render node when customRenderNodes has no entry', function ()
{
node.run(
mockDrawingContext,
mockGameObject,
mockParentMatrix,
null,
mockTexturerNode,
mockTransformerNode
);
expect(mockBatchHandler.batch).toHaveBeenCalledOnce();
});
it('should call batch on customRenderNodes entry when present', function ()
{
var customBatch = { batch: vi.fn() };
mockGameObject.customRenderNodes['BatchHandler'] = customBatch;
node.run(
mockDrawingContext,
mockGameObject,
mockParentMatrix,
null,
mockTexturerNode,
mockTransformerNode
);
expect(customBatch.batch).toHaveBeenCalledOnce();
expect(mockBatchHandler.batch).not.toHaveBeenCalled();
});
it('should call texturerNode.run when it has a run method', function ()
{
mockTexturerNode.run = vi.fn();
node.run(
mockDrawingContext,
mockGameObject,
mockParentMatrix,
null,
mockTexturerNode,
mockTransformerNode
);
expect(mockTexturerNode.run).toHaveBeenCalledWith(mockDrawingContext, mockGameObject, null);
});
it('should call transformerNode.run when it has a run method', function ()
{
mockTransformerNode.run = vi.fn();
node.run(
mockDrawingContext,
mockGameObject,
mockParentMatrix,
null,
mockTexturerNode,
mockTransformerNode
);
expect(mockTransformerNode.run).toHaveBeenCalledWith(
mockDrawingContext,
mockGameObject,
mockTexturerNode,
mockParentMatrix,
null
);
});
it('should call tinterNode.run when tinterNode has a run method', function ()
{
var mockTinterNode = {
run: vi.fn(),
tintEffect: 1,
tintTopLeft: 0xff0000,
tintBottomLeft: 0x00ff00,
tintTopRight: 0x0000ff,
tintBottomRight: 0xffffff
};
node.run(
mockDrawingContext,
mockGameObject,
mockParentMatrix,
null,
mockTexturerNode,
mockTransformerNode,
mockTinterNode
);
expect(mockTinterNode.run).toHaveBeenCalledWith(mockDrawingContext, mockGameObject, null);
});
it('should use tinterNode tint values when tinterNode is provided', function ()
{
var mockTinterNode = {
tintEffect: 2,
tintTopLeft: 0xaabbcc,
tintBottomLeft: 0x112233,
tintTopRight: 0x445566,
tintBottomRight: 0x778899
};
node.run(
mockDrawingContext,
mockGameObject,
mockParentMatrix,
null,
mockTexturerNode,
mockTransformerNode,
mockTinterNode
);
var batchArgs = mockBatchHandler.batch.mock.calls[0];
// indices: 0=ctx, 1=glTex, 2-9=quad(8), 10=u0, 11=v0, 12=width, 13=height, 14=tintEffect, 15-18=tints, 19=renderOptions, 20-27=uvQuad
expect(batchArgs[14]).toBe(2); // tintEffect
expect(batchArgs[15]).toBe(0xaabbcc); // tintTopLeft
expect(batchArgs[16]).toBe(0x112233); // tintBottomLeft
expect(batchArgs[17]).toBe(0x445566); // tintTopRight
expect(batchArgs[18]).toBe(0x778899); // tintBottomRight
});
it('should use gameObject tint values when tinterNode is not provided', function ()
{
mockGameObject.tintMode = 3;
node.run(
mockDrawingContext,
mockGameObject,
mockParentMatrix,
null,
mockTexturerNode,
mockTransformerNode
);
var batchArgs = mockBatchHandler.batch.mock.calls[0];
expect(batchArgs[14]).toBe(3); // tintEffect from gameObject.tintMode
});
it('should pass the glTexture from frame.source to batch', function ()
{
var glTex = { id: 'texture-1' };
mockTexturerNode.frame.source.glTexture = glTex;
node.run(
mockDrawingContext,
mockGameObject,
mockParentMatrix,
null,
mockTexturerNode,
mockTransformerNode
);
var batchArgs = mockBatchHandler.batch.mock.calls[0];
expect(batchArgs[1]).toBe(glTex);
});
it('should pass the drawing context as the first argument to batch', function ()
{
var ctx = { id: 'ctx-1' };
node.run(
ctx,
mockGameObject,
mockParentMatrix,
null,
mockTexturerNode,
mockTransformerNode
);
var batchArgs = mockBatchHandler.batch.mock.calls[0];
expect(batchArgs[0]).toBe(ctx);
});
it('should pass uvQuad coordinates to batch after renderOptions', function ()
{
var uvQuad = new Float32Array([ 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8 ]);
mockTexturerNode.uvMatrix.quad = uvQuad;
node.run(
mockDrawingContext,
mockGameObject,
mockParentMatrix,
null,
mockTexturerNode,
mockTransformerNode
);
var batchArgs = mockBatchHandler.batch.mock.calls[0];
// renderOptions is at index 19, uvQuad TL.x at 20
expect(batchArgs[20]).toBeCloseTo(uvQuad[0]); // TL x
expect(batchArgs[21]).toBeCloseTo(uvQuad[1]); // TL y
expect(batchArgs[22]).toBeCloseTo(uvQuad[2]); // BL x
expect(batchArgs[23]).toBeCloseTo(uvQuad[3]); // BL y
expect(batchArgs[24]).toBeCloseTo(uvQuad[6]); // TR x
expect(batchArgs[25]).toBeCloseTo(uvQuad[7]); // TR y
expect(batchArgs[26]).toBeCloseTo(uvQuad[4]); // BR x
expect(batchArgs[27]).toBeCloseTo(uvQuad[5]); // BR y
});
it('should add gameObject.tileRotation to _lightingOptions.normalMapRotation', function ()
{
mockGameObject.tileRotation = 1.5;
node._lightingOptions.normalMapRotation = 0;
// We need lighting to be enabled to see the rotation in renderOptions,
// but tileRotation is added regardless. Verify via _lightingOptions directly.
node.run(
mockDrawingContext,
mockGameObject,
mockParentMatrix,
null,
mockTexturerNode,
mockTransformerNode
);
// After run, normalMapRotation should have tileRotation added.
// setRenderOptions resets it first (NaN path sets from gameObject.rotation which is undefined here)
// The line `this._lightingOptions.normalMapRotation += gameObject.tileRotation` always runs.
expect(node._lightingOptions.normalMapRotation).toBeCloseTo(1.5);
});
it('should pass UV width and height derived from frame u0/v0/u1/v1 to batch', function ()
{
mockTexturerNode.frame.u0 = 0.25;
mockTexturerNode.frame.v0 = 0.125;
mockTexturerNode.frame.u1 = 0.75;
mockTexturerNode.frame.v1 = 0.875;
node.run(
mockDrawingContext,
mockGameObject,
mockParentMatrix,
null,
mockTexturerNode,
mockTransformerNode
);
var batchArgs = mockBatchHandler.batch.mock.calls[0];
// indices: 0=ctx, 1=glTex, 2-9=quad(8 values), 10=u0, 11=v0, 12=width(u1-u0), 13=height(v1-v0)
expect(batchArgs[10]).toBeCloseTo(0.25); // u0
expect(batchArgs[11]).toBeCloseTo(0.125); // v0
expect(batchArgs[12]).toBeCloseTo(0.5); // u1 - u0
expect(batchArgs[13]).toBeCloseTo(0.75); // v1 - v0
});
it('should pass _renderOptions with wrapFrame true to batch', function ()
{
node.run(
mockDrawingContext,
mockGameObject,
mockParentMatrix,
null,
mockTexturerNode,
mockTransformerNode
);
var batchArgs = mockBatchHandler.batch.mock.calls[0];
// renderOptions is at index 19 (after tintEffect + 4 tint values = indices 14-18)
expect(batchArgs[19]).toBe(node._renderOptions);
expect(batchArgs[19].wrapFrame).toBe(true);
});
});
});