Skip to content

Instantly share code, notes, and snippets.

@pypy-vrc
Created February 28, 2024 07:05
Show Gist options
  • Save pypy-vrc/bd9e3b01c3992fa3d07188951c76d441 to your computer and use it in GitHub Desktop.
Save pypy-vrc/bd9e3b01c3992fa3d07188951c76d441 to your computer and use it in GitHub Desktop.
riot games tex file converter
/**
* @param {Buffer} data
* @returns {Buffer}
*/
const tex_to_dds = (data) => {
if (data.byteLength < 12 || data.subarray(0, 4).toString() !== "TEX\0") {
throw new Error("invalid TEX file");
}
const width = data.readUInt16LE(4);
const height = data.readUInt16LE(6);
const format = data.readUInt8(9);
const hasMipmaps = data.readUint8(11);
const ddspf = Buffer.alloc(32);
ddspf.writeUInt32LE(32, 0);
switch (format) {
case 10: // DXT1
ddspf.writeUInt32LE(0x4, 4);
ddspf.write("DXT1", 8);
break;
case 12: // DXT5
ddspf.writeUInt32LE(0x4, 4);
ddspf.write("DXT5", 8);
break;
case 20: // RGBA8
ddspf.writeUInt32LE(0x41, 4);
ddspf.writeUInt32LE(32, 8);
ddspf.writeUInt32LE(0x000000ff, 12);
ddspf.writeUInt32LE(0x0000ff00, 16);
ddspf.writeUInt32LE(0x00ff0000, 20);
ddspf.writeUInt32LE(0xff000000, 24);
break;
default:
throw new Error(`unsupported TEX format: ${format}`);
}
let pixels;
if (hasMipmaps) {
// Note: only convert the largest mipmap
let blockSize = 0;
let bytesPerBlock = 0;
switch (format) {
case 10: // DXT1
blockSize = 4;
bytesPerBlock = 8;
break;
case 12: // DXT5
blockSize = 4;
bytesPerBlock = 16;
break;
case 20: // RGBA8
blockSize = 4;
bytesPerBlock = 4;
break;
}
// Find mipmap count
// let mipmapCount = 0;
// for (let i = Math.max(width, height); i > 0; i >>= 1) {
// ++mipmapCount;
// }
const blockWidth = Math.floor((width + blockSize - 1) / blockSize);
const blockheight = Math.floor((height + blockSize - 1) / blockSize);
const mipmapSize = bytesPerBlock * blockWidth * blockheight;
pixels = data.subarray(-mipmapSize);
} else {
pixels = data.subarray(12);
}
const ddsHeader = Buffer.alloc(128);
ddsHeader.write("DDS ", 0);
ddsHeader.writeUInt32LE(124, 4);
ddsHeader.writeUInt32LE(0x1007, 8);
ddsHeader.writeUInt32LE(height, 12);
ddsHeader.writeUInt32LE(width, 16);
ddspf.copy(ddsHeader, 76);
ddsHeader.writeUInt32LE(0x1000, 108);
return Buffer.concat([ddsHeader, pixels]);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment