mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-22 11:17:05 +02:00
feat: pvr parser
This commit is contained in:
1 parent
12ee9d381d
commit
376b3f04e5
5 files changed
+264
-47
No files matched your search
@@ -1,8 +1,10 @@
|
||||
import { existsSync } from 'fs';
|
||||
import { clamp } from 'lodash';
|
||||
import sharp from 'sharp';
|
||||
import { Vector3Tuple } from 'three';
|
||||
import { readDVPLFile } from '../blitz/readDVPLFile';
|
||||
import { DdsStream } from '../streams/dds';
|
||||
import { PvrStream } from '../streams/pvr';
|
||||
|
||||
export enum TextureMutation {
|
||||
Normal,
|
||||
@@ -24,28 +26,32 @@ type ReadTextureOptions =
|
||||
|
||||
export async function readTexture(path: string, options?: ReadTextureOptions) {
|
||||
const ddsTexturePath = path.replace('.tex', '.dx11.dds.dvpl');
|
||||
const decompressedDvpl = await readDVPLFile(ddsTexturePath);
|
||||
const stream = new DdsStream(decompressedDvpl);
|
||||
const dds = await stream.dds();
|
||||
const channels = 4 * dds.width * dds.height;
|
||||
const isDds = existsSync(ddsTexturePath);
|
||||
const resolvedTexturePath = isDds
|
||||
? ddsTexturePath
|
||||
: ddsTexturePath.replace('.dds', '.pvr');
|
||||
const decompressedDvpl = await readDVPLFile(resolvedTexturePath);
|
||||
const raw = isDds
|
||||
? await new DdsStream(decompressedDvpl).dds()
|
||||
: new PvrStream(decompressedDvpl).pvr();
|
||||
const channels = 4 * raw.width * raw.height;
|
||||
|
||||
/**
|
||||
* Red is always 255 and blue is always 0. Only alpha and green contain any
|
||||
* sort of information.
|
||||
*/
|
||||
switch (options?.mutation) {
|
||||
case TextureMutation.Normal: {
|
||||
for (let index = 0; index < channels; index += 4) {
|
||||
// TODO: this math is pretty sus and looks very goofy when rendered
|
||||
let x = dds.data[index + 3] * (2 / 255) - 1;
|
||||
let y = dds.data[index + 1] * (2 / 255) - 1;
|
||||
/**
|
||||
* Red is always 255 and blue is always 0. Only alpha and green contain any
|
||||
* sort of information.
|
||||
*/
|
||||
let x = raw.data[index + 3] * (2 / 255) - 1;
|
||||
let y = raw.data[index + 1] * (2 / 255) - 1;
|
||||
const underSqrt = 1 - x ** 2 - y ** 2;
|
||||
let z = underSqrt > 0 ? Math.sqrt(underSqrt) : -Math.sqrt(-underSqrt);
|
||||
|
||||
dds.data[index] = Math.round((x + 1) * (255 / 2));
|
||||
dds.data[index + 1] = Math.round((y + 1) * (255 / 2));
|
||||
dds.data[index + 2] = Math.round((z + 1) * (255 / 2));
|
||||
dds.data[index + 3] = 255;
|
||||
raw.data[index] = Math.round((x + 1) * (255 / 2));
|
||||
raw.data[index + 1] = Math.round((y + 1) * (255 / 2));
|
||||
raw.data[index + 2] = Math.round((z + 1) * (255 / 2));
|
||||
raw.data[index + 3] = 255;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -53,13 +59,16 @@ export async function readTexture(path: string, options?: ReadTextureOptions) {
|
||||
|
||||
case TextureMutation.RoughnessMetallicness: {
|
||||
for (let index = 0; index < channels; index += 4) {
|
||||
const metallicness = dds.data[index + 1];
|
||||
const roughness = dds.data[index + 3];
|
||||
/**
|
||||
* Same channel situation as normal maps.
|
||||
*/
|
||||
const metallicness = raw.data[index + 1];
|
||||
const roughness = raw.data[index + 3];
|
||||
|
||||
dds.data[index] = 0;
|
||||
dds.data[index + 1] = roughness;
|
||||
dds.data[index + 2] = metallicness;
|
||||
dds.data[index + 3] = 255;
|
||||
raw.data[index] = 0;
|
||||
raw.data[index + 1] = roughness;
|
||||
raw.data[index + 2] = metallicness;
|
||||
raw.data[index + 3] = 255;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -69,36 +78,24 @@ export async function readTexture(path: string, options?: ReadTextureOptions) {
|
||||
for (let index = 0; index < channels; index += 4) {
|
||||
// treating as pre multiplied but I can't fully confirm
|
||||
|
||||
const r = dds.data[index] / 255;
|
||||
const g = dds.data[index + 1] / 255;
|
||||
const b = dds.data[index + 2] / 255;
|
||||
const a = dds.data[index + 3] / 255;
|
||||
const r = raw.data[index] / 255;
|
||||
const g = raw.data[index + 1] / 255;
|
||||
const b = raw.data[index + 2] / 255;
|
||||
const a = raw.data[index + 3] / 255;
|
||||
const invA = 1 - a;
|
||||
const rPrime = r + invA * options.baseColor[0];
|
||||
const gPrime = g + invA * options.baseColor[1];
|
||||
const bPrime = b + invA * options.baseColor[2];
|
||||
|
||||
dds.data[index] = Math.round(clamp(rPrime * 255, 0, 255));
|
||||
dds.data[index + 1] = Math.round(clamp(gPrime * 255, 0, 255));
|
||||
dds.data[index + 2] = Math.round(clamp(bPrime * 255, 0, 255));
|
||||
dds.data[index + 3] = 255;
|
||||
raw.data[index] = Math.round(clamp(rPrime * 255, 0, 255));
|
||||
raw.data[index + 1] = Math.round(clamp(gPrime * 255, 0, 255));
|
||||
raw.data[index + 2] = Math.round(clamp(bPrime * 255, 0, 255));
|
||||
raw.data[index + 3] = 255;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return await sharp(dds.data, { raw: dds }).png().toBuffer();
|
||||
|
||||
// const isDds = existsSync(ddsTexturePath);
|
||||
// const resolvedTexturePath = isDds
|
||||
// ? ddsTexturePath
|
||||
// : ddsTexturePath.replace('.dds', '.pvr');
|
||||
// const decompressedTexture = await readDVPLFile(resolvedTexturePath);
|
||||
// const jpg = await toJpg(decompressedTexture, {
|
||||
// ...options,
|
||||
// format: isDds ? 'dds' : 'pvr',
|
||||
// });
|
||||
|
||||
// return jpg;
|
||||
return await sharp(raw.data, { raw: raw }).png().toBuffer();
|
||||
}
|
||||
Reference in new issue
Block a user