diff --git a/src/core/streams/bc1.ts b/src/core/streams/bc1.ts index 2583397d4..b19770468 100644 --- a/src/core/streams/bc1.ts +++ b/src/core/streams/bc1.ts @@ -1,13 +1,13 @@ import { times } from 'lodash'; import { Vector4Tuple } from 'three'; -import { BinaryStream } from './binary'; +import { BitStream } from './bit'; const MAX_UINT5 = 2 ** 5 - 1; const MAX_UINT6 = 2 ** 6 - 1; type InterpolationKey = 0b00 | 0b01 | 0b10 | 0b11; -export class Bc1Stream extends BinaryStream { +export class Bc1Stream extends BitStream { color() { const r = this.consume(5) / MAX_UINT5; const g = this.consume(6) / MAX_UINT6; @@ -17,18 +17,27 @@ export class Bc1Stream extends BinaryStream { } interpolation() { + const color0Numeric = this.readBytes(2).readUInt16LE(); const color0 = this.color(); + const color1Numeric = this.readBytes(2).readUInt16LE(); const color1 = this.color(); - const color2 = color0.map( - (channel0, index) => (channel0 + color1[index]) / 2, + const alpha = color0Numeric > color1Numeric; + const color2 = color0.map((channel0, index) => + alpha + ? (1 / 2) * channel0 + (1 / 2) * color1[index] + : (2 / 3) * channel0 + (1 / 3) * color1[index], ); - const color3 = [...color2.slice(0, -1), 0]; + const color3 = alpha + ? [0, 0, 0, 0] + : color0.map( + (channel0, index) => (1 / 3) * channel0 + (2 / 3) * color1[index], + ); return { [0b00]: color0, - [0b01]: color1, - [0b10]: color2, - [0b11]: color3, + [0b01]: color0, + [0b10]: color0, + [0b11]: color0, }; } @@ -53,8 +62,7 @@ export class Bc1Stream extends BinaryStream { throw new RangeError('Width and height must be divisible by 4'); } - const count = (width / 4) * (height / 4); - const blocks = this.blocks(count); + const blocks = this.blocks((width / 4) * (height / 4)); const image = Buffer.alloc(width * height * 4); let pixelIndex = 0; diff --git a/src/core/streams/binary.ts b/src/core/streams/bit.ts similarity index 72% rename from src/core/streams/binary.ts rename to src/core/streams/bit.ts index c00951a62..5d7e7da83 100644 --- a/src/core/streams/binary.ts +++ b/src/core/streams/bit.ts @@ -1,6 +1,8 @@ +import { times } from 'lodash'; + type Bit = 0 | 1; -export class BinaryStream { +export class BitStream { public index = 0; bits: Bit[] = []; @@ -18,6 +20,10 @@ export class BinaryStream { this.index += size; } read(size: number) { + if (size > 32) { + throw new RangeError('Cannot read more than 32 bits at a time'); + } + if (this.index + size > this.bits.length) { throw new RangeError('Cannot read beyond end of stream'); } @@ -26,6 +32,12 @@ export class BinaryStream { .slice(this.index, this.index + size) .reduce((accumulator, bit) => (accumulator << 1) | bit, 0 as number); } + readBytes(size: number) { + const buffer = Buffer.from(times(size, () => this.consume(8))); + this.skip(-8 * size); + + return buffer; + } consume(size: number) { const value = this.read(size); this.skip(size); diff --git a/src/core/streams/primitive.ts b/src/core/streams/byte.ts similarity index 97% rename from src/core/streams/primitive.ts rename to src/core/streams/byte.ts index 4a84330b2..5bb18202d 100644 --- a/src/core/streams/primitive.ts +++ b/src/core/streams/byte.ts @@ -1,4 +1,4 @@ -export class PrimitiveStream { +export class ByteStream { public index = 0; constructor(public stream: Buffer) {} diff --git a/src/core/streams/dds.ts b/src/core/streams/dds.ts index eaeb15d91..e511dd4c3 100644 --- a/src/core/streams/dds.ts +++ b/src/core/streams/dds.ts @@ -177,6 +177,7 @@ enum DdsCaps2 { export class DdsStream extends WindowsStream { async dds() { this.magicNumber(); + const header = this.header(); if ( @@ -190,8 +191,11 @@ export class DdsStream extends WindowsStream { switch (headerDxt10.dxgiFormat) { case DxgiFormat.BC1_UNORM_SRGB: { + this.skip(1); + const image = new Bc1Stream( - this.consume((header.width / 4) * (header.height / 4) * 8), + // this.consume((header.width / 4) * (header.height / 4) * 8), + this.consumeRemaining(), ).bc1(header.width, header.height); writeFileSync( @@ -257,11 +261,11 @@ export class DdsStream extends WindowsStream { headerDxt10() { return { - dxgiFormat: this.uint() as DxgiFormat, - resourceDimension: this.uint() as DdsDimension, - miscFlag: this.uint(), - arraySize: this.uint(), - miscFlags2: this.uint(), + dxgiFormat: this.dword() as DxgiFormat, + resourceDimension: this.dword() as DdsDimension, + miscFlag: this.dword(), + arraySize: this.dword(), + miscFlags2: this.dword(), }; } } diff --git a/src/core/streams/scpg.ts b/src/core/streams/scpg.ts index 24d6c9a8f..0e29b3acf 100644 --- a/src/core/streams/scpg.ts +++ b/src/core/streams/scpg.ts @@ -1,5 +1,5 @@ import { times } from 'lodash'; -import { PrimitiveStream } from './primitive'; +import { ByteStream } from './byte'; enum KAType { NONE = 0, @@ -55,7 +55,7 @@ export enum VertexAttribute { CUBETEXCOORD3 = 19, } -export class ScpgStream extends PrimitiveStream { +export class ScpgStream extends ByteStream { vectorN(size: number) { return times(size, () => this.float()); } diff --git a/src/core/streams/windows.ts b/src/core/streams/windows.ts index ee5b71146..6860cdf98 100644 --- a/src/core/streams/windows.ts +++ b/src/core/streams/windows.ts @@ -1,11 +1,7 @@ -import { PrimitiveStream } from './primitive'; +import { ByteStream } from './byte'; -export class WindowsStream extends PrimitiveStream { +export class WindowsStream extends ByteStream { dword() { return this.uint32(); } - - uint() { - return this.uint32(); - } }