mdx-m3-viewer
Version:
A browser WebGL model viewer. Mainly focused on models of the games Warcraft 3 and Starcraft 2.
91 lines • 4.09 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const math_1 = require("../../common/math");
/**
* Some tools allow to setup fake mipmaps.
* These are mipmaps that use the same JPG data as other mipmaps.
* This is technically not valid, but can work properly in the game.
* Not always though.
* Sadly I don't quite know the rules.
*/
function isMipmapFake(whichMipmap, mipmapOffsets) {
const offset = mipmapOffsets[whichMipmap];
for (let i = 0; i < whichMipmap; i++) {
if (mipmapOffsets[i] === offset) {
return true;
}
}
return false;
}
/**
* Tests for issues in BLP textures.
*/
function sanityTest(texture) {
const nodes = [];
const content = texture.content;
const alphaBits = texture.alphaBits;
const mipmapOffsets = texture.mipmapOffsets;
const mipmapSizes = texture.mipmapSizes;
let width = texture.width;
let height = texture.height;
if (content !== 0 && content !== 1) {
nodes.push({ type: 'warning', message: 'Unknown content type' });
}
if (alphaBits !== 0 && alphaBits !== 1 && alphaBits !== 4 && alphaBits !== 8) {
nodes.push({ type: 'warning', message: `Expected alpha bits to be 0, 1, 4, or 8, but got ${alphaBits}` });
}
if (width > 512 || height > 512) {
nodes.push({ type: 'warning', message: `Expected width and height up to 512, but got ${width}x${height}` });
}
if (content === 0) {
const jpgHeader = texture.jpgHeader;
if (jpgHeader.length > 624) {
nodes.push({ type: 'warning', message: `Expected the JPG header to be at most 624 bytes, but got ${jpgHeader.length}` });
}
}
if (!(0, math_1.isPowerOfTwo)(width) || !(0, math_1.isPowerOfTwo)(height)) {
nodes.push({ type: 'warning', message: `Expected the width and height to be powers of two, but got ${width}x${height}` });
}
for (let i = 0; i < 16; i++) {
if (mipmapSizes[i] > 0) {
// This happens if this mipmap level supposedly exists, but we already passed the level that should have been last.
if (width < 1 && height < 1) {
nodes.push({ type: 'warning', message: `Mipmap ${i}: this mipmap should not exist` });
}
else if (isMipmapFake(i, mipmapOffsets)) {
nodes.push({ type: 'warning', message: `Mipmap ${i}: this mipmap is fake` });
}
else {
// In the case this is not a square texture, one dimension will get to size 1 before the other.
width = Math.max(width, 1);
height = Math.max(height, 1);
let mipmapData;
try {
mipmapData = texture.getMipmap(i);
}
catch (e) {
nodes.push({ type: 'warning', message: `Mipmap ${i}: Decoding failed` });
}
if (mipmapData) {
if (content === 0) {
if (mipmapData.width !== width || mipmapData.height !== height) {
nodes.push({ type: 'warning', message: `Mipmap ${i}: the JPG width (${mipmapData.width}) and height (${mipmapData.height}) do not match the mipmap width (${width}) and height (${height})` });
}
}
else if (content === 1) {
const pixels = width * height;
const size = pixels + Math.ceil((pixels * alphaBits) / 8);
if (size !== mipmapSizes[i]) {
nodes.push({ type: 'warning', message: `Mipmap ${i}: the declared size is ${mipmapSizes[i]}, but the real size is ${size}` });
}
}
}
}
}
width >>= 1;
height >>= 1;
}
return { nodes, warnings: nodes.length };
}
exports.default = sanityTest;
//# sourceMappingURL=sanitytest.js.map
;