mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-31 09:01:42 +00:00
152 lines
4.5 KiB
TypeScript
152 lines
4.5 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
|
|
import { createGameView, gameViewGeometry } from '@/utils/gameView'
|
|
|
|
describe('gameViewGeometry', () => {
|
|
it('center-crops a widescreen game view for 3:4 portrait output', () => {
|
|
const geometry = gameViewGeometry(1920, 1080, 540, 720)
|
|
expect(Array.from(geometry.textureCoordinates)).toEqual([
|
|
expect.closeTo(0.29, 2),
|
|
0,
|
|
expect.closeTo(0.71, 2),
|
|
0,
|
|
expect.closeTo(0.29, 2),
|
|
1,
|
|
expect.closeTo(0.71, 2),
|
|
1,
|
|
])
|
|
})
|
|
|
|
it('keeps the full game view for 16:9 landscape output', () => {
|
|
const geometry = gameViewGeometry(1920, 1080, 720, 405)
|
|
expect(Array.from(geometry.textureCoordinates)).toEqual([
|
|
0, 0, 1, 0, 0, 1, 1, 1,
|
|
])
|
|
})
|
|
|
|
it('keeps the full texture when both aspect ratios match', () => {
|
|
const geometry = gameViewGeometry(1600, 900, 800, 450)
|
|
expect(Array.from(geometry.textureCoordinates)).toEqual([
|
|
0, 0, 1, 0, 0, 1, 1, 1,
|
|
])
|
|
})
|
|
|
|
it('keeps 0.5x full-frame while higher zoom levels crop around the center', () => {
|
|
const wideGeometry = gameViewGeometry(1920, 1080, 540, 720, 0.5)
|
|
expect(Array.from(wideGeometry.textureCoordinates)).toEqual([
|
|
expect.closeTo(0.29, 2),
|
|
0,
|
|
expect.closeTo(0.71, 2),
|
|
0,
|
|
expect.closeTo(0.29, 2),
|
|
1,
|
|
expect.closeTo(0.71, 2),
|
|
1,
|
|
])
|
|
expect(Array.from(wideGeometry.positions)).toEqual([
|
|
-1, -1, 1, -1, -1, 1, 1, 1,
|
|
])
|
|
|
|
const zoomedGeometry = gameViewGeometry(1920, 1080, 540, 720, 2)
|
|
expect(Array.from(zoomedGeometry.textureCoordinates)).toEqual([
|
|
expect.closeTo(0.39, 2),
|
|
0.25,
|
|
expect.closeTo(0.61, 2),
|
|
0.25,
|
|
expect.closeTo(0.39, 2),
|
|
0.75,
|
|
expect.closeTo(0.61, 2),
|
|
0.75,
|
|
])
|
|
})
|
|
})
|
|
|
|
describe('createGameView', () => {
|
|
it('recreates graphics resources and resumes after context restoration', () => {
|
|
const gl = {
|
|
ARRAY_BUFFER: 1,
|
|
CLAMP_TO_EDGE: 2,
|
|
COLOR_BUFFER_BIT: 4,
|
|
COMPILE_STATUS: 5,
|
|
DYNAMIC_DRAW: 6,
|
|
FLOAT: 7,
|
|
FRAGMENT_SHADER: 8,
|
|
LINK_STATUS: 9,
|
|
MIRRORED_REPEAT: 10,
|
|
NEAREST: 11,
|
|
REPEAT: 12,
|
|
RGBA: 13,
|
|
STATIC_DRAW: 14,
|
|
TEXTURE_2D: 15,
|
|
TEXTURE_MAG_FILTER: 16,
|
|
TEXTURE_MIN_FILTER: 17,
|
|
TEXTURE_WRAP_S: 18,
|
|
TEXTURE_WRAP_T: 19,
|
|
TRIANGLE_STRIP: 20,
|
|
UNSIGNED_BYTE: 21,
|
|
VERTEX_SHADER: 22,
|
|
attachShader: vi.fn(),
|
|
bindBuffer: vi.fn(),
|
|
bindTexture: vi.fn(),
|
|
bufferData: vi.fn(),
|
|
clear: vi.fn(),
|
|
clearColor: vi.fn(),
|
|
compileShader: vi.fn(),
|
|
createBuffer: vi.fn(() => ({})),
|
|
createProgram: vi.fn(() => ({})),
|
|
createShader: vi.fn(() => ({})),
|
|
createTexture: vi.fn(() => ({})),
|
|
deleteBuffer: vi.fn(),
|
|
deleteProgram: vi.fn(),
|
|
deleteShader: vi.fn(),
|
|
deleteTexture: vi.fn(),
|
|
drawArrays: vi.fn(),
|
|
enableVertexAttribArray: vi.fn(),
|
|
finish: vi.fn(),
|
|
getAttribLocation: vi.fn((_program, name: string) =>
|
|
name === 'a_position' ? 0 : 1,
|
|
),
|
|
getExtension: vi.fn(() => ({ loseContext: vi.fn() })),
|
|
getProgramInfoLog: vi.fn(() => ''),
|
|
getProgramParameter: vi.fn(() => true),
|
|
getShaderInfoLog: vi.fn(() => ''),
|
|
getShaderParameter: vi.fn(() => true),
|
|
getUniformLocation: vi.fn(() => ({})),
|
|
linkProgram: vi.fn(),
|
|
shaderSource: vi.fn(),
|
|
texImage2D: vi.fn(),
|
|
texParameterf: vi.fn(),
|
|
uniform1i: vi.fn(),
|
|
useProgram: vi.fn(),
|
|
vertexAttribPointer: vi.fn(),
|
|
viewport: vi.fn(),
|
|
}
|
|
const canvas = Object.assign(new EventTarget(), {
|
|
getContext: () => gl,
|
|
height: 0,
|
|
width: 0,
|
|
}) as unknown as HTMLCanvasElement
|
|
const restored = vi.fn()
|
|
vi.spyOn(console, 'error').mockImplementation(() => undefined)
|
|
vi.spyOn(console, 'info').mockImplementation(() => undefined)
|
|
const view = createGameView(canvas, { onContextRestored: restored })
|
|
view.resize(540, 720, 1920, 1080, 2)
|
|
|
|
const lost = new Event('webglcontextlost', { cancelable: true })
|
|
canvas.dispatchEvent(lost)
|
|
expect(lost.defaultPrevented).toBe(true)
|
|
expect(view.isLost()).toBe(true)
|
|
|
|
canvas.dispatchEvent(new Event('webglcontextrestored'))
|
|
expect(view.isLost()).toBe(false)
|
|
expect(restored).toHaveBeenCalledOnce()
|
|
expect(gl.createProgram).toHaveBeenCalledTimes(2)
|
|
expect(canvas.width).toBe(540)
|
|
expect(canvas.height).toBe(720)
|
|
|
|
view.render()
|
|
expect(gl.drawArrays).toHaveBeenCalledOnce()
|
|
view.dispose()
|
|
})
|
|
})
|