UNPKG

vtf-js

Version:

A javascript IO library for the Valve Texture Format.

84 lines (83 loc) 3.59 kB
import { CompressImage, DecompressImage, DxtFlags } from 'libsquish-js'; import { registerCodec, VImageData, VEncodedImageData, getCodec } from '../core/image.js'; import { VFormats } from '../core/enums.js'; import { ceil4 } from '../core/utils.js'; function padImage(img) { const width = ceil4(img.width); const height = ceil4(img.height); const src_u32 = new Uint32Array(img.data.buffer); const out_u32 = new Uint32Array(width * height); for (let y = 0; y < height; y++) { if (y >= img.height) continue; for (let x = 0; x < width; x++) { if (x >= img.width) continue; out_u32[y * width + x] = src_u32[y * img.width + x]; } } return new VImageData(new Uint8Array(out_u32.buffer), img.width, img.height); } function cropImage(img) { const width = ceil4(img.width); const src_u32 = new Uint32Array(img.data.buffer); const out_u32 = new Uint32Array(img.width * img.height); for (let y = 0; y < img.height; y++) { for (let x = 0; x < img.width; x++) { out_u32[y * img.width + x] = src_u32[y * width + x]; } } return new VImageData(new Uint8Array(out_u32.buffer), img.width, img.height); } registerCodec(VFormats.DXT1, { length(width, height) { return ceil4(width) * ceil4(height) * 0.5; }, encode(image) { const padded = padImage(image.convert(Uint8Array)); const input = { data: padded.data, width: ceil4(padded.width), height: ceil4(padded.height) }; const encoded = CompressImage(input, DxtFlags.kDxt1); return new VEncodedImageData(encoded, image.width, image.height, VFormats.DXT1); }, decode(image) { const input = { data: image.data, width: ceil4(image.width), height: ceil4(image.height) }; const decoded = DecompressImage(input, DxtFlags.kDxt1); const cropped = cropImage(new VImageData(decoded, image.width, image.height)); return cropped; }, }); registerCodec(VFormats.DXT1_ONEBITALPHA, getCodec(VFormats.DXT1)); registerCodec(VFormats.DXT3, { length(width, height) { return ceil4(width) * ceil4(height); }, encode(image) { const padded = padImage(image.convert(Uint8Array)); const input = { data: padded.data, width: ceil4(padded.width), height: ceil4(padded.height) }; const encoded = CompressImage(input, DxtFlags.kDxt3); return new VEncodedImageData(encoded, image.width, image.height, VFormats.DXT3); }, decode(image) { const input = { data: image.data, width: ceil4(image.width), height: ceil4(image.height) }; const decoded = DecompressImage(input, DxtFlags.kDxt3); const cropped = cropImage(new VImageData(decoded, image.width, image.height)); return cropped; }, }); registerCodec(VFormats.DXT5, { length(width, height) { return ceil4(width) * ceil4(height); }, encode(image) { const padded = padImage(image.convert(Uint8Array)); const input = { data: padded.data, width: ceil4(padded.width), height: ceil4(padded.height) }; const encoded = CompressImage(input, DxtFlags.kDxt5); return new VEncodedImageData(encoded, image.width, image.height, VFormats.DXT5); }, decode(image) { const input = { data: image.data, width: ceil4(image.width), height: ceil4(image.height) }; const decoded = DecompressImage(input, DxtFlags.kDxt5); const cropped = cropImage(new VImageData(decoded, image.width, image.height)); return cropped; }, });