1
0
Fork 0
doom-wad-php/tests/Unit/Texture/TextureResolverTest.php
2026-04-22 16:41:48 +02:00

135 lines
3.7 KiB
PHP

<?php
use Doom\Texture\TextureResolver;
use Doom\Wad\File;
use Doom\Wad\Types\Lump;
function s16(int $value): string
{
return pack('v', $value & 0xFFFF);
}
/**
* @param array<int, array{originX:int, originY:int, patch:int, stepDir:int, colorMap:int}> $patches
*/
function textureRecord(string $name, bool $masked, int $width, int $height, array $patches): string
{
$data = pack('a8VvvVv', $name, $masked ? 1 : 0, $width, $height, 0, count($patches));
foreach ($patches as $patch) {
$data .= s16($patch['originX']);
$data .= s16($patch['originY']);
$data .= pack('v', $patch['patch']);
$data .= pack('v', $patch['stepDir']);
$data .= pack('v', $patch['colorMap']);
}
return $data;
}
/**
* @param string[] $records
*/
function textureXData(array $records): string
{
$count = count($records);
$offset = 4 + ($count * 4);
$offsets = [];
$body = '';
foreach ($records as $record) {
$offsets[] = $offset;
$body .= $record;
$offset += strlen($record);
}
$data = pack('V', $count);
foreach ($offsets as $itemOffset) {
$data .= pack('V', $itemOffset);
}
return $data . $body;
}
/**
* @param string[] $names
*/
function pnamesData(array $names): string
{
$data = pack('V', count($names));
foreach ($names as $name) {
$data .= pack('a8', $name);
}
return $data;
}
function appendLump(File $wad, string $name, string $data): void
{
$index = $wad->lumps->count();
$wad->lumps->push(new Lump(
offset: 0,
size: strlen($data),
name: strtoupper($name),
data: $data,
index: $index,
));
}
test('resolves textures using PNAMES and patch lumps', function (): void {
$wad = new File();
appendLump($wad, 'PNAMES', pnamesData(['PATCHA', 'PATCHB']));
appendLump($wad, 'TEXTURE1', textureXData([
textureRecord('TEXA', false, 64, 64, [
['originX' => 0, 'originY' => 0, 'patch' => 0, 'stepDir' => 0, 'colorMap' => 0],
]),
textureRecord('TEXB', false, 32, 16, [
['originX' => 8, 'originY' => -2, 'patch' => 0, 'stepDir' => 0, 'colorMap' => 0],
]),
]));
appendLump($wad, 'TEXTURE2', textureXData([
textureRecord('TEXA', true, 128, 32, [
['originX' => 4, 'originY' => 5, 'patch' => 1, 'stepDir' => 0, 'colorMap' => 0],
['originX' => 0, 'originY' => 0, 'patch' => 5, 'stepDir' => 0, 'colorMap' => 0],
]),
]));
appendLump($wad, 'PATCHA', '');
$resolved = $wad->resolveTextures();
expect($resolved)->toHaveCount(2);
expect($resolved)->toHaveKey('TEXA');
expect($resolved)->toHaveKey('TEXB');
$texA = $resolved['TEXA'];
expect($texA->masked)->toBeTrue();
expect($texA->width)->toBe(128);
expect($texA->height)->toBe(32);
expect($texA->patches)->toHaveCount(2);
expect($texA->patches[0]->patchName)->toBe('PATCHB');
expect($texA->patches[0]->lumpIndex)->toBeNull();
expect($texA->patches[0]->isResolved())->toBeFalse();
expect($texA->patches[1]->patchName)->toBeNull();
$texB = TextureResolver::forWad($wad)->resolveByName('texb');
expect($texB)->not->toBeNull();
expect($texB->patches[0]->patchName)->toBe('PATCHA');
expect($texB->patches[0]->lumpIndex)->toBe(3);
expect($texB->patches[0]->isResolved())->toBeTrue();
});
test('throws when PNAMES lump is missing', function (): void {
$wad = new File();
appendLump($wad, 'TEXTURE1', textureXData([
textureRecord('TEXA', false, 16, 16, [
['originX' => 0, 'originY' => 0, 'patch' => 0, 'stepDir' => 0, 'colorMap' => 0],
]),
]));
expect(fn () => $wad->resolveTextures())->toThrow(RuntimeException::class);
});