mirror of
https://github.com/BinomialLLC/basis_universal.git
synced 2026-08-05 12:59:03 +00:00
Adding new fields to the basis header: texture type and framerate. Texture type may be 2D, 2D array, video, volume, or cubemap array. The compressor makes sure that anything other than pure 2D follows certain constraints (cubemap arrays must have a multiple of 6 input images, videos/texture array images all must have the same resolution/# of mipmaps, etc.) When unpacking cubemaps, the -unpack command now writes cubemap .KTX files which various tools like PVRTexTool support.
319 lines
8.0 KiB
HTML
319 lines
8.0 KiB
HTML
<html>
|
|
<head>
|
|
<script src="basis.js"></script>
|
|
<script src="renderer.js"></script>
|
|
<script src="dxt-to-rgb565.js"></script>
|
|
<script type="text/javascript">
|
|
function log(s) {
|
|
var div = document.createElement('div');
|
|
div.innerHTML = s;
|
|
document.getElementById('logger').appendChild(div);
|
|
}
|
|
|
|
function logTime(desc, t) {
|
|
log(t + 'ms ' + desc);
|
|
}
|
|
|
|
function isDef(v) {
|
|
return typeof v != 'undefined';
|
|
}
|
|
|
|
function elem(id) {
|
|
return document.getElementById(id);
|
|
}
|
|
|
|
formatTable = function(rows) {
|
|
var colLengths = [];
|
|
|
|
for (var i = 0; i < rows.length; i++) {
|
|
var row = rows[i];
|
|
for (var j = 0; j < row.length; j++) {
|
|
if (colLengths.length <= j) colLengths.push(0);
|
|
if (colLengths[j] < row[j].length) colLengths[j] = row[j].length;
|
|
}
|
|
}
|
|
|
|
function formatRow(row) {
|
|
var parts = [];
|
|
for (var i = 0; i < colLengths.length; i++) {
|
|
var s = row.length > i ? row[i] : '';
|
|
var padding = (new Array(1 + colLengths[i] - s.length)).join(' ');
|
|
if (s && s[0] >= '0' && s[0] <= '9') {
|
|
// Right-align numbers.
|
|
parts.push(padding + s);
|
|
} else {
|
|
parts.push(s + padding);
|
|
}
|
|
}
|
|
return parts.join(' | ');
|
|
}
|
|
|
|
var width = 0;
|
|
for (var i = 0; i < colLengths.length; i++) {
|
|
width += colLengths[i];
|
|
// Add another 3 for the separator.
|
|
if (i != 0) width += 3;
|
|
}
|
|
|
|
var lines = [];
|
|
lines.push(formatRow(rows[0]));
|
|
lines.push((new Array(width + 1)).join('-'));
|
|
for (var i = 1; i < rows.length; i++) {
|
|
lines.push(formatRow(rows[i]));
|
|
}
|
|
|
|
return lines.join('\n');
|
|
};
|
|
|
|
|
|
function loadArrayBuffer(uri, callback) {
|
|
log('Loading ' + uri + '...');
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.responseType = "arraybuffer";
|
|
xhr.open('GET', uri, true);
|
|
xhr.onreadystatechange = function(e) {
|
|
if (xhr.readyState == 4 && xhr.status == 200) {
|
|
callback(xhr.response);
|
|
}
|
|
}
|
|
xhr.send(null);
|
|
}
|
|
|
|
// DXT formats, from:
|
|
// http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
|
|
COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
|
|
COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
|
|
COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
|
|
COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
|
|
|
|
BASIS_FORMAT = {
|
|
|
|
cTFETC1: 0,
|
|
cTFBC1: 1,
|
|
cTFBC4: 2,
|
|
cTFPVRTC1_4_OPAQUE_ONLY: 3,
|
|
cTFBC7_M6_OPAQUE_ONLY: 4,
|
|
cTFETC2: 5,
|
|
cTFBC3: 6,
|
|
cTFBC5: 7,
|
|
};
|
|
|
|
BASIS_FORMAT_NAMES = {};
|
|
for (var name in BASIS_FORMAT) {
|
|
BASIS_FORMAT_NAMES[BASIS_FORMAT[name]] = name;
|
|
}
|
|
|
|
DXT_FORMAT_MAP = {};
|
|
DXT_FORMAT_MAP[BASIS_FORMAT.cTFBC1] = COMPRESSED_RGB_S3TC_DXT1_EXT;
|
|
DXT_FORMAT_MAP[BASIS_FORMAT.cTFBC3] = COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
|
|
|
var dxtSupported = true;
|
|
var drawMode = 0;
|
|
|
|
var tex, width, height, images, levels, have_alpha, alignedWidth, alignedHeight, format;
|
|
|
|
function redraw()
|
|
{
|
|
if (!width)
|
|
return;
|
|
|
|
if (dxtSupported)
|
|
{
|
|
renderer.drawTexture(tex, alignedWidth, alignedHeight, drawMode);
|
|
}
|
|
else if (format == BASIS_FORMAT.cTFBC1)
|
|
{
|
|
renderer.drawTexture(tex, alignedWidth, alignedHeight, drawMode);
|
|
}
|
|
else
|
|
{
|
|
log('TODO: Implement BC3->RGBA conversion for browsers that don\'t support BC3');
|
|
}
|
|
}
|
|
|
|
function dataLoaded(data)
|
|
{
|
|
log('Done loading .basis file, decoded header:');
|
|
|
|
Module._basis_init();
|
|
|
|
var srcSize = data.byteLength;
|
|
var bytes = new Uint8Array(data);
|
|
var src = Module._malloc(srcSize);
|
|
arrayBufferCopy(bytes, Module.HEAPU8, src, srcSize);
|
|
|
|
var basisHandle = Module._basis_open(src, srcSize);
|
|
if (!basisHandle)
|
|
{
|
|
log('Failed opening basis file!');
|
|
width = 0;
|
|
return;
|
|
}
|
|
|
|
width = Module._basis_get_image_width(basisHandle, 0, 0);
|
|
height = Module._basis_get_image_height(basisHandle, 0, 0);
|
|
images = Module._basis_get_num_images(basisHandle, 0);
|
|
levels = Module._basis_get_num_levels(basisHandle, 0);
|
|
has_alpha = Module._basis_get_has_alpha(basisHandle);
|
|
|
|
if (!width || !height || !images || !levels)
|
|
{
|
|
Module._basis_close(basisHandle);
|
|
Module._free(src);
|
|
width = 0;
|
|
|
|
log('Failed getting info from basis file!');
|
|
return;
|
|
}
|
|
|
|
format = BASIS_FORMAT.cTFBC1;
|
|
if (has_alpha)
|
|
{
|
|
format = BASIS_FORMAT.cTFBC3;
|
|
|
|
log('Decoding .basis data to BC3');
|
|
}
|
|
else
|
|
{
|
|
log('Decoding .basis data to BC1');
|
|
}
|
|
|
|
log('width: ' + width);
|
|
log('height: ' + height);
|
|
log('images: ' + images);
|
|
log('first image mipmap levels: ' + levels);
|
|
log('has_alpha: ' + has_alpha);
|
|
|
|
alignedWidth = (width + 3) & ~3;
|
|
alignedHeight = (height + 3) & ~3;
|
|
|
|
var canvas = elem('canvas');
|
|
canvas.width = alignedWidth;
|
|
canvas.height = alignedHeight;
|
|
|
|
var status = Module._basis_start_transcoding(basisHandle);
|
|
if (!status)
|
|
{
|
|
Module._basis_close(basisHandle);
|
|
Module._free(src);
|
|
width = 0;
|
|
|
|
log('basis_start_transcoding() failed!');
|
|
return;
|
|
}
|
|
|
|
var dstSize = Module._basis_get_image_transcoded_size_in_bytes(basisHandle, 0, 0, format);
|
|
var dst = Module._malloc(dstSize);
|
|
|
|
if (!Module._basis_transcode_image(basisHandle, dst, dstSize, 0, 0, format, 1, 0))
|
|
{
|
|
Module._basis_close(basisHandle);
|
|
Module._free(src);
|
|
Module._free(dst);
|
|
width = 0;
|
|
|
|
log('basis_transcode_image() failed!');
|
|
return;
|
|
}
|
|
|
|
var dxtData = new Uint8Array(Module.HEAPU8.buffer, dst, dstSize);
|
|
|
|
if (dxtSupported)
|
|
{
|
|
tex = renderer.createDxtTexture(dxtData, alignedWidth, alignedHeight, DXT_FORMAT_MAP[format]);
|
|
}
|
|
else
|
|
{
|
|
var rgb565Data = dxtToRgb565(Module.HEAPU16, dst / 2, alignedWidth, alignedHeight);
|
|
|
|
tex = renderer.createRgb565Texture(rgb565Data, alignedWidth, alignedHeight);
|
|
}
|
|
|
|
redraw();
|
|
|
|
Module._free(dst);
|
|
Module._basis_close(basisHandle);
|
|
Module._free(src);
|
|
}
|
|
|
|
/**
|
|
* @param {Uint8Array} src
|
|
* @param {Uint8Array} dst
|
|
*/
|
|
function arrayBufferCopy(src, dst, dstByteOffset, numBytes) {
|
|
dst32Offset = dstByteOffset / 4;
|
|
var tail = (numBytes % 4);
|
|
var src32 = new Uint32Array(src.buffer, 0, (numBytes - tail) / 4);
|
|
var dst32 = new Uint32Array(dst.buffer);
|
|
for (var i = 0; i < src32.length; i++) {
|
|
dst32[dst32Offset + i] = src32[i];
|
|
}
|
|
for (var i = numBytes - tail; i < numBytes; i++) {
|
|
dst[dstByteOffset + i] = src[i];
|
|
}
|
|
}
|
|
|
|
|
|
function run() {
|
|
elem('logger').innerHTML = '';
|
|
loadArrayBuffer(elem('file').value, dataLoaded);
|
|
}
|
|
|
|
|
|
function initialize() {
|
|
var gl = elem('canvas').getContext('experimental-webgl');
|
|
// Load the DXT extension, and verify it exists.
|
|
if (!gl.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc')) {
|
|
dxtSupported = false;
|
|
elem('nodxt').style.display = 'block';
|
|
}
|
|
|
|
window.renderer = new Renderer(gl);
|
|
|
|
elem('file').addEventListener('keydown', function(e) {
|
|
if (e.keyCode == 13) {
|
|
run();
|
|
}
|
|
}, false);
|
|
|
|
run();
|
|
}
|
|
|
|
function alphaBlend() { drawMode = 0; redraw(); }
|
|
function viewRGB() { drawMode = 1; redraw(); }
|
|
function viewAlpha() { drawMode = 2; redraw(); }
|
|
|
|
</script>
|
|
</head>
|
|
<body onload="initialize()">
|
|
<br>
|
|
<div style="font-size: 24pt; font-weight: bold">
|
|
.basis->BC1/BC3 transcoder test
|
|
</div>
|
|
|
|
<br>This demo uses the Basis C++ transcoder (compiled to Javascript using Emscripten) to transcode a .basis file to BC1/BC3.
|
|
<br>Thanks to Evan Parker for providing <a href="https://github.com/toji/webgl-texture-utils">webgl-texture-utils</a> and this test bed.
|
|
<br>
|
|
<br>
|
|
.basis file:
|
|
<input id="file" type="text" size=30 value="kodim20.basis"></input>
|
|
<input type="button" value="Run!" onclick="run()"></input>
|
|
<br>
|
|
<br>
|
|
<input type="button" value="Alpha blend" onclick="alphaBlend()"></input>
|
|
<input type="button" value="View RGB" onclick="viewRGB()"></input>
|
|
<input type="button" value="View Alpha" onclick="viewAlpha()"></input>
|
|
|
|
<div style="position:absolute; left: 525px; top:130px; font-size: 20pt; font-weight: bold; color: red">
|
|
<div id="nodxt" style="display: none; width: 768px; font-size: 20pt; font-weight: bold; color: red">
|
|
NOTE: Your browser does not support DXT, so using RGB565
|
|
for the texture below. To get DXT, try Chrome 19+
|
|
(beta channel as of 2012-04-20; graphics card DXT support also required).
|
|
</div>
|
|
<canvas id='canvas'></canvas>
|
|
</div>
|
|
<br><br>
|
|
<div id='logger'></div>
|
|
</body>
|
|
</html>
|