mirror of
https://github.com/BinomialLLC/basis_universal.git
synced 2026-09-18 08:24:31 +00:00
By default, emscripten's generated javascript modules lives in the global object "Module'. This makes it impossible to load multiple emscripten modules on the same page. In attempt to avoid namespace collision, this change modularizes the emscripten build so the Module is instead called 'BASIS'. Many target applications for Basis are likely to already be using other emscripten modules. Testing: The existing webgl/(texture|gltf) pages have been updated to use the new name and seem to operate as before
281 lines
7.2 KiB
HTML
281 lines
7.2 KiB
HTML
<html>
|
|
<head>
|
|
<script src="renderer.js"></script>
|
|
<script src="dxt-to-rgb565.js"></script>
|
|
<script src="../transcoder/build/basis_transcoder.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:');
|
|
|
|
const { BasisFile, initializeBasis } = Module;
|
|
initializeBasis();
|
|
|
|
const startTime = performance.now();
|
|
|
|
const basisFile = new BasisFile(new Uint8Array(data));
|
|
|
|
width = basisFile.getImageWidth(0, 0);
|
|
height = basisFile.getImageHeight(0, 0);
|
|
images = basisFile.getNumImages();
|
|
levels = basisFile.getNumLevels(0);
|
|
has_alpha = basisFile.getHasAlpha();
|
|
|
|
if (!width || !height || !images || !levels) {
|
|
console.warn('Invalid .basis file');
|
|
basisFile.close();
|
|
basisFile.delete();
|
|
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');
|
|
}
|
|
|
|
if (!basisFile.startTranscoding()) {
|
|
console.warn('startTranscoding failed');
|
|
basisFile.close();
|
|
basisFile.delete();
|
|
return;
|
|
}
|
|
|
|
const dstSize = basisFile.getImageTranscodedSizeInBytes(0, 0, format);
|
|
const dst = new Uint8Array(dstSize);
|
|
|
|
if (!basisFile.transcodeImage(dst, 0, 0, format, 1, 0)) {
|
|
console.warn('transcodeImage failed');
|
|
basisFile.close();
|
|
basisFile.delete();
|
|
return;
|
|
}
|
|
|
|
const elapsed = performance.now() - startTime;
|
|
|
|
basisFile.close();
|
|
basisFile.delete();
|
|
|
|
log('width: ' + width);
|
|
log('height: ' + height);
|
|
log('images: ' + images);
|
|
log('first image mipmap levels: ' + levels);
|
|
log('has_alpha: ' + has_alpha);
|
|
logTime('transcoding time', elapsed.toFixed(2));
|
|
|
|
alignedWidth = (width + 3) & ~3;
|
|
alignedHeight = (height + 3) & ~3;
|
|
|
|
var canvas = elem('canvas');
|
|
canvas.width = alignedWidth;
|
|
canvas.height = alignedHeight;
|
|
|
|
if (dxtSupported)
|
|
{
|
|
tex = renderer.createDxtTexture(dst, alignedWidth, alignedHeight, DXT_FORMAT_MAP[format]);
|
|
}
|
|
else
|
|
{
|
|
var rgb565Data = dxtToRgb565(new Uint16Array(dst.buffer), 0, alignedWidth, alignedHeight);
|
|
|
|
tex = renderer.createRgb565Texture(rgb565Data, alignedWidth, alignedHeight);
|
|
}
|
|
|
|
redraw();
|
|
}
|
|
|
|
function runLoadFile() {
|
|
elem('logger').innerHTML = '';
|
|
loadArrayBuffer(elem('file').value, dataLoaded);
|
|
}
|
|
|
|
function alphaBlend() { drawMode = 0; redraw(); }
|
|
function viewRGB() { drawMode = 1; redraw(); }
|
|
function viewAlpha() { drawMode = 2; redraw(); }
|
|
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<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="assets/kodim20.basis"></input>
|
|
<input type="button" value="Run!" onclick="runLoadFile()"></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>
|
|
<script>
|
|
BASIS({onRuntimeInitialized : () => {
|
|
var gl = elem('canvas').getContext('webgl');
|
|
// Load the DXT extension, and verify it exists.
|
|
if (!gl.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc') && !gl.getExtension('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) {
|
|
runLoadFile();
|
|
}
|
|
}, false);
|
|
|
|
runLoadFile();
|
|
}}).then(module => window.Module = module);
|
|
</script>
|
|
</html>
|