UNPKG

phaser

Version:

A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.

534 lines (468 loc) 19 kB
var Utils = require('../../../src/renderer/webgl/Utils'); describe('Phaser.Renderer.WebGL.Utils.getTintFromFloats', function () { describe('getTintFromFloats', function () { it('should return 0 for all zero components', function () { expect(Utils.getTintFromFloats(0, 0, 0, 0)).toBe(0); }); it('should return correct packed value for white fully opaque', function () { // r=1, g=1, b=1, a=1 => 0xFFFFFFFF expect(Utils.getTintFromFloats(1, 1, 1, 1)).toBe(0xFFFFFFFF >>> 0); }); it('should pack red component correctly', function () { // r=1, g=0, b=0, a=1 => ua=0xFF, ur=0xFF, ug=0, ub=0 => 0xFFFF0000 expect(Utils.getTintFromFloats(1, 0, 0, 1)).toBe(0xFFFF0000 >>> 0); }); it('should pack green component correctly', function () { // r=0, g=1, b=0, a=1 => 0xFF00FF00 expect(Utils.getTintFromFloats(0, 1, 0, 1)).toBe(0xFF00FF00 >>> 0); }); it('should pack blue component correctly', function () { // r=0, g=0, b=1, a=1 => 0xFF0000FF expect(Utils.getTintFromFloats(0, 0, 1, 1)).toBe(0xFF0000FF >>> 0); }); it('should pack alpha component into the high byte', function () { // r=0, g=0, b=0, a=1 => 0xFF000000 expect(Utils.getTintFromFloats(0, 0, 0, 1)).toBe(0xFF000000 >>> 0); }); it('should return an unsigned 32-bit integer', function () { var result = Utils.getTintFromFloats(1, 1, 1, 1); expect(result).toBeGreaterThanOrEqual(0); expect(result).toBeLessThanOrEqual(0xFFFFFFFF); }); it('should handle mid-range values', function () { var r = 0.5, g = 0.25, b = 0.75, a = 0.5; var ur = ((r * 255) | 0) & 0xff; var ug = ((g * 255) | 0) & 0xff; var ub = ((b * 255) | 0) & 0xff; var ua = ((a * 255) | 0) & 0xff; var expected = ((ua << 24) | (ur << 16) | (ug << 8) | ub) >>> 0; expect(Utils.getTintFromFloats(r, g, b, a)).toBe(expected); }); it('should truncate float components via bitwise OR', function () { // 0.999 * 255 = 254.745 => 254 => 0xFE var result = Utils.getTintFromFloats(0.999, 0, 0, 0); var ur = ((0.999 * 255) | 0) & 0xff; var expected = ((0 << 24) | (ur << 16) | (0 << 8) | 0) >>> 0; expect(result).toBe(expected); }); }); describe('getTintAppendFloatAlpha', function () { it('should return the rgb value when alpha is 0', function () { expect(Utils.getTintAppendFloatAlpha(0x00FF0000, 0)).toBe(0x00FF0000 >>> 0); }); it('should pack full alpha into high byte', function () { // rgb=0x112233, a=1 => 0xFF112233 expect(Utils.getTintAppendFloatAlpha(0x112233, 1)).toBe(0xFF112233 >>> 0); }); it('should pack zero alpha into high byte', function () { // rgb=0xFF0000, a=0 => 0x00FF0000 expect(Utils.getTintAppendFloatAlpha(0xFF0000, 0)).toBe(0x00FF0000 >>> 0); }); it('should pack mid-range alpha correctly', function () { var rgb = 0xABCDEF; var a = 0.5; var ua = ((a * 255) | 0) & 0xff; var expected = ((ua << 24) | rgb) >>> 0; expect(Utils.getTintAppendFloatAlpha(rgb, a)).toBe(expected); }); it('should return an unsigned 32-bit integer', function () { var result = Utils.getTintAppendFloatAlpha(0xFFFFFF, 1); expect(result).toBeGreaterThanOrEqual(0); expect(result).toBeLessThanOrEqual(0xFFFFFFFF); }); it('should handle zero rgb with full alpha', function () { expect(Utils.getTintAppendFloatAlpha(0, 1)).toBe(0xFF000000 >>> 0); }); }); describe('getTintAppendFloatAlphaAndSwap', function () { it('should swap red and blue channels', function () { // rgb = 0xFF0000 (red), a=1 => after swap: ub=0xFF at bits 16, ur=0 at bits 0 // result = (0xFF << 24) | (0xFF << 16) | (0 << 8) | 0 => 0xFFFF0000 // Wait: ur = (0xFF0000 >> 16) = 0xFF, ug = 0, ub = 0 // swapped: (ua<<24)|(ub<<16)|(ug<<8)|ur = (0xFF<<24)|(0<<16)|(0<<8)|0xFF = 0xFF0000FF expect(Utils.getTintAppendFloatAlphaAndSwap(0xFF0000, 1)).toBe(0xFF0000FF >>> 0); }); it('should leave green channel unchanged', function () { // rgb = 0x00FF00 (green), a=1 // ur=0, ug=0xFF, ub=0 // swapped: (0xFF<<24)|(0<<16)|(0xFF<<8)|0 => 0xFF00FF00 expect(Utils.getTintAppendFloatAlphaAndSwap(0x00FF00, 1)).toBe(0xFF00FF00 >>> 0); }); it('should swap blue to red position', function () { // rgb = 0x0000FF (blue), a=1 // ur=0, ug=0, ub=0xFF // swapped: (0xFF<<24)|(0xFF<<16)|(0<<8)|0 => 0xFFFF0000 expect(Utils.getTintAppendFloatAlphaAndSwap(0x0000FF, 1)).toBe(0xFFFF0000 >>> 0); }); it('should return zero for all zero inputs', function () { expect(Utils.getTintAppendFloatAlphaAndSwap(0, 0)).toBe(0); }); it('should return an unsigned 32-bit integer', function () { var result = Utils.getTintAppendFloatAlphaAndSwap(0xFFFFFF, 1); expect(result).toBeGreaterThanOrEqual(0); expect(result).toBeLessThanOrEqual(0xFFFFFFFF); }); it('should produce same result as non-swap when r equals b', function () { // If r == b, swap doesn't change the rgb value var rgb = 0x884488; // r=0x88, g=0x44, b=0x88 var a = 0.8; var ua = ((a * 255) | 0) & 0xff; var ur = (rgb >> 16) & 0xff; // 0x88 var ug = (rgb >> 8) & 0xff; // 0x44 var ub = rgb & 0xff; // 0x88 var expected = ((ua << 24) | (ub << 16) | (ug << 8) | ur) >>> 0; expect(Utils.getTintAppendFloatAlphaAndSwap(rgb, a)).toBe(expected); }); }); describe('getFloatsFromUintRGB', function () { it('should return [0, 0, 0] for zero input', function () { var result = Utils.getFloatsFromUintRGB(0); expect(result[0]).toBe(0); expect(result[1]).toBe(0); expect(result[2]).toBe(0); }); it('should return [1, 1, 1] for 0xFFFFFF', function () { var result = Utils.getFloatsFromUintRGB(0xFFFFFF); expect(result[0]).toBeCloseTo(1, 5); expect(result[1]).toBeCloseTo(1, 5); expect(result[2]).toBeCloseTo(1, 5); }); it('should return array of length 3', function () { var result = Utils.getFloatsFromUintRGB(0x804020); expect(result.length).toBe(3); }); it('should extract red channel correctly', function () { // 0xFF0000 => r=255, g=0, b=0 var result = Utils.getFloatsFromUintRGB(0xFF0000); expect(result[0]).toBeCloseTo(1, 5); expect(result[1]).toBe(0); expect(result[2]).toBe(0); }); it('should extract green channel correctly', function () { // 0x00FF00 => r=0, g=255, b=0 var result = Utils.getFloatsFromUintRGB(0x00FF00); expect(result[0]).toBe(0); expect(result[1]).toBeCloseTo(1, 5); expect(result[2]).toBe(0); }); it('should extract blue channel correctly', function () { // 0x0000FF => r=0, g=0, b=255 var result = Utils.getFloatsFromUintRGB(0x0000FF); expect(result[0]).toBe(0); expect(result[1]).toBe(0); expect(result[2]).toBeCloseTo(1, 5); }); it('should return values in the range 0 to 1', function () { var result = Utils.getFloatsFromUintRGB(0x7F3FA0); expect(result[0]).toBeGreaterThanOrEqual(0); expect(result[0]).toBeLessThanOrEqual(1); expect(result[1]).toBeGreaterThanOrEqual(0); expect(result[1]).toBeLessThanOrEqual(1); expect(result[2]).toBeGreaterThanOrEqual(0); expect(result[2]).toBeLessThanOrEqual(1); }); it('should correctly convert mid-range values', function () { // 0x804020 => r=128, g=64, b=32 var result = Utils.getFloatsFromUintRGB(0x804020); expect(result[0]).toBeCloseTo(128 / 255, 5); expect(result[1]).toBeCloseTo(64 / 255, 5); expect(result[2]).toBeCloseTo(32 / 255, 5); }); it('should round-trip via getTintFromFloats approximately', function () { var r = 0.5, g = 0.25, b = 0.75; var packed = Utils.getTintFromFloats(r, g, b, 0); // packed has alpha in high byte, rgb in lower 24 bits var rgb = packed & 0xFFFFFF; var result = Utils.getFloatsFromUintRGB(rgb); expect(result[0]).toBeCloseTo(r, 1); expect(result[1]).toBeCloseTo(g, 1); expect(result[2]).toBeCloseTo(b, 1); }); }); describe('checkShaderMax', function () { it('should return gpuMax when maxTextures is 0', function () { var gl = { MAX_TEXTURE_IMAGE_UNITS: 0x8872, getParameter: function (param) { return 32; } }; expect(Utils.checkShaderMax(gl, 0)).toBe(16); }); it('should return gpuMax when maxTextures is -1', function () { var gl = { MAX_TEXTURE_IMAGE_UNITS: 0x8872, getParameter: function (param) { return 32; } }; expect(Utils.checkShaderMax(gl, -1)).toBe(16); }); it('should clamp gpuMax to 16 even if GPU supports more', function () { var gl = { MAX_TEXTURE_IMAGE_UNITS: 0x8872, getParameter: function (param) { return 64; } }; expect(Utils.checkShaderMax(gl, -1)).toBe(16); }); it('should return the smaller of gpuMax and maxTextures', function () { var gl = { MAX_TEXTURE_IMAGE_UNITS: 0x8872, getParameter: function (param) { return 8; } }; expect(Utils.checkShaderMax(gl, 4)).toBe(4); }); it('should return gpuMax when maxTextures exceeds gpuMax', function () { var gl = { MAX_TEXTURE_IMAGE_UNITS: 0x8872, getParameter: function (param) { return 8; } }; expect(Utils.checkShaderMax(gl, 16)).toBe(8); }); it('should cap at 16 even when gpu reports 32 and maxTextures is 20', function () { var gl = { MAX_TEXTURE_IMAGE_UNITS: 0x8872, getParameter: function (param) { return 32; } }; expect(Utils.checkShaderMax(gl, 20)).toBe(16); }); it('should return 1 when both gpuMax and maxTextures are 1', function () { var gl = { MAX_TEXTURE_IMAGE_UNITS: 0x8872, getParameter: function (param) { return 1; } }; expect(Utils.checkShaderMax(gl, 1)).toBe(1); }); }); describe('updateLightingUniforms', function () { it('should return early when lightManager does not exist', function () { var programManager = { setUniform: vi.fn(), removeUniform: vi.fn() }; var drawingContext = { camera: { scene: { sys: { lights: null } } }, height: 600 }; Utils.updateLightingUniforms(true, drawingContext, programManager, 1, {}, false, 0, 0); expect(programManager.setUniform).not.toHaveBeenCalled(); expect(programManager.removeUniform).not.toHaveBeenCalled(); }); it('should return early when lightManager.active is false', function () { var programManager = { setUniform: vi.fn(), removeUniform: vi.fn() }; var drawingContext = { camera: { scene: { sys: { lights: { active: false } } } }, height: 600 }; Utils.updateLightingUniforms(true, drawingContext, programManager, 1, {}, false, 0, 0); expect(programManager.setUniform).not.toHaveBeenCalled(); expect(programManager.removeUniform).not.toHaveBeenCalled(); }); it('should call removeUniform for lighting keys when enable is false', function () { var programManager = { setUniform: vi.fn(), removeUniform: vi.fn() }; var drawingContext = { camera: { scene: { sys: { lights: { active: true, getLights: function () { return []; }, ambientColor: { r: 1, g: 1, b: 1 } } } }, x: 0, y: 0, rotation: 0, zoom: 1 }, height: 600 }; Utils.updateLightingUniforms(false, drawingContext, programManager, 1, {}, false, 0, 0); expect(programManager.removeUniform).toHaveBeenCalledWith('uNormSampler'); expect(programManager.removeUniform).toHaveBeenCalledWith('uCamera'); expect(programManager.removeUniform).toHaveBeenCalledWith('uAmbientLightColor'); expect(programManager.removeUniform).toHaveBeenCalledWith('uLightCount'); expect(programManager.removeUniform).toHaveBeenCalledWith('uPenumbra'); expect(programManager.removeUniform).toHaveBeenCalledWith('uDiffuseFlatThreshold'); }); it('should call setUniform for base lighting keys when enable is true with no lights', function () { var programManager = { setUniform: vi.fn(), removeUniform: vi.fn() }; var drawingContext = { camera: { scene: { sys: { lights: { active: true, getLights: function () { return []; }, ambientColor: { r: 0.2, g: 0.2, b: 0.2 } } } }, x: 10, y: 20, rotation: 0, zoom: 1 }, height: 600 }; var vec = { x: 0, y: 0 }; Utils.updateLightingUniforms(true, drawingContext, programManager, 2, vec, false, 0, 0); expect(programManager.setUniform).toHaveBeenCalledWith('uNormSampler', 2); expect(programManager.setUniform).toHaveBeenCalledWith('uCamera', [10, 20, 0, 1]); expect(programManager.setUniform).toHaveBeenCalledWith('uAmbientLightColor', [0.2, 0.2, 0.2]); expect(programManager.setUniform).toHaveBeenCalledWith('uLightCount', 0); }); it('should set self-shadow uniforms when selfShadow is true', function () { var programManager = { setUniform: vi.fn(), removeUniform: vi.fn() }; var drawingContext = { camera: { scene: { sys: { lights: { active: true, getLights: function () { return []; }, ambientColor: { r: 1, g: 1, b: 1 } } } }, x: 0, y: 0, rotation: 0, zoom: 1 }, height: 600 }; var vec = { x: 0, y: 0 }; Utils.updateLightingUniforms(true, drawingContext, programManager, 1, vec, true, 0.3, 0.5); expect(programManager.setUniform).toHaveBeenCalledWith('uDiffuseFlatThreshold', 0.5 * 3); expect(programManager.setUniform).toHaveBeenCalledWith('uPenumbra', 0.3); }); it('should not set self-shadow uniforms when selfShadow is false', function () { var programManager = { setUniform: vi.fn(), removeUniform: vi.fn() }; var drawingContext = { camera: { scene: { sys: { lights: { active: true, getLights: function () { return []; }, ambientColor: { r: 1, g: 1, b: 1 } } } }, x: 0, y: 0, rotation: 0, zoom: 1 }, height: 600 }; var vec = { x: 0, y: 0 }; var setUniformCalls = []; programManager.setUniform = function (name, val) { setUniformCalls.push(name); }; Utils.updateLightingUniforms(true, drawingContext, programManager, 1, vec, false, 0, 0); expect(setUniformCalls.indexOf('uDiffuseFlatThreshold')).toBe(-1); expect(setUniformCalls.indexOf('uPenumbra')).toBe(-1); }); }); });