mirror of
https://github.com/BinomialLLC/basis_universal.git
synced 2026-06-13 10:49:14 +00:00
Restructure webgl demo folders and Update readme
This commit is contained in:
@@ -59,11 +59,9 @@ If you are doing rate distortion comparisons vs. other similar systems, be sure
|
||||
|
||||
### WebGL test
|
||||
|
||||
The "WebGL" directory contains a very simple WebGL demo that uses the transcoder compiled to asm.js with [emscripten](https://emscripten.org/). It currently only supports transcoding to the BC1 and BC3 texture formats. The file `WebGL/basis_wrappers.cpp` contains a simple C-style API that the Javascript code calls to interface with the C++ Basis transcoder.
|
||||
The "WebGL" directory contains two very simple WebGL demos that use the transcoder compiled to wasm with [emscripten](https://emscripten.org/).
|
||||
|
||||
On browsers that don't support BC1 (Firefox is one), there's a low-quality fallback code path for opaque textures (but no fallback for BC3 yet). Note that the fallback path only converts to 16-bit RGB images at the moment, so the quality isn't as good as it should be.
|
||||
|
||||
Note that I was unable to disable assertions when compiling the transcoder in release (-O2), and I'm not sure why yet. Currently, basisu.h forcefully #undef's the assert() macro, which is ugly but works. Including assert()'s in release will slow transcoding down.
|
||||
See more details [here](webgl/README.md).
|
||||
|
||||
### Transcoder details
|
||||
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
# glTF Demo
|
||||
# WebGL Demo
|
||||
|
||||
A WebGL demo rendering a glTF 3D model with `.basis` texture files, transcoded into one of the following compressed texture formats:
|
||||
### Texture Demo
|
||||
|
||||
`index.html` uses the transcoder compiled to wasm with emscripten and renders the texture. Currently supporting following texture formats:
|
||||
* BC1
|
||||
* BC3
|
||||
|
||||
On browsers that don't support BC1 (Firefox is one), there's a low-quality fallback code path for opaque textures (but no fallback for BC3 yet). Note that the fallback path only converts to 16-bit RGB images at the moment, so the quality isn't as good as it should be.
|
||||
|
||||
### glTF 3D Model Demo
|
||||
`gltf-demo/index.html` renders a glTF 3D model with `.basis` texture files, transcoded into one of the following compressed texture formats:
|
||||
* DTX (BC1)
|
||||
* Tested in Chrome (Linux and macOS) and Firefox (macOS).
|
||||
* ETC1
|
||||
@@ -9,11 +17,11 @@ A WebGL demo rendering a glTF 3D model with `.basis` texture files, transcoded i
|
||||
* PVRTC (COMPRESSED_RGB_PVRTC_4BPPV1_IMG)
|
||||
* Tested in Chrome and Safari on iOS iPhone 6 Plus.
|
||||
|
||||
Requires WebAssembly and WebGL support.
|
||||
|
||||
The glTF model in this demo uses a hypothetical `GOOGLE_texture_basis` extension. That extension is defined for the sake of example only – the glTF format will officially embed Basis files within a KTX2 wrapper, through a new
|
||||
extension that is currently in development.
|
||||
|
||||
Both demos requires WebAssembly and WebGL support.
|
||||
|
||||
## Testing locally
|
||||
|
||||
See [how to run things locally](https://threejs.org/docs/#manual/en/introduction/How-to-run-things-locally), or (with [Node.js](https://nodejs.org/en/) installed), run:
|
||||
@@ -29,7 +37,7 @@ The console will display a `localhost` URL for local testing, and (on supported
|
||||
Prebuilt versions of `basis_transcoder.js` and `basis_transcoder.wasm` are included in the `wasm/build/` folder, and are sufficient for local demos. To build the transcoder yourself, first install emscripten ([tutorial](https://webassembly.org/getting-started/developers-guide/)) and cmake ([download](https://cmake.org/download/)). Then run:
|
||||
|
||||
```shell
|
||||
cd webgl/gltf-demo/wasm/build/
|
||||
cd webgl/wasm/build/
|
||||
emcmake cmake ../
|
||||
make
|
||||
```
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,228 +1,205 @@
|
||||
// basis_wrappers.cpp - Simple C-style wrappers to the C++ transcoder for WebGL use.
|
||||
// basis_wrappers.cpp - Simple C-style wrappers to the C++ transcoder for WebGL use.
|
||||
#include "basisu_transcoder.h"
|
||||
#include <emscripten/bind.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace emscripten;
|
||||
using namespace basist;
|
||||
|
||||
static basist::etc1_global_selector_codebook *g_pGlobal_codebook;
|
||||
|
||||
typedef unsigned int uint;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void basis_init();
|
||||
|
||||
void *basis_open(void *src, uint src_size);
|
||||
void basis_close(void *h);
|
||||
|
||||
uint basis_get_has_alpha(void *h);
|
||||
|
||||
uint basis_get_num_images(void *h);
|
||||
uint basis_get_num_levels(void *h, uint image_index);
|
||||
|
||||
uint basis_get_image_width(void *h, uint image_index, uint level_index);
|
||||
uint basis_get_image_height(void *h, uint image_index, uint level_index);
|
||||
|
||||
uint basis_get_image_transcoded_size_in_bytes(void *h, uint image_index, uint level_index, uint format);
|
||||
|
||||
uint basis_start_transcoding(void *h);
|
||||
|
||||
uint basis_transcode_image(void *h, void *dst, uint dst_size_in_bytes,
|
||||
uint image_index, uint level_index, uint format,
|
||||
uint pvrtc_wrap_addressing, uint get_alpha_for_opaque_formats);
|
||||
}
|
||||
|
||||
void basis_init()
|
||||
{
|
||||
basisu_transcoder_init();
|
||||
|
||||
if (!g_pGlobal_codebook)
|
||||
g_pGlobal_codebook = new basist::etc1_global_selector_codebook(g_global_selector_cb_size, g_global_selector_cb);
|
||||
basisu_transcoder_init();
|
||||
|
||||
if (!g_pGlobal_codebook)
|
||||
g_pGlobal_codebook = new basist::etc1_global_selector_codebook(g_global_selector_cb_size, g_global_selector_cb);
|
||||
}
|
||||
|
||||
#define MAGIC 0xDEADBEE1
|
||||
|
||||
struct basis_file
|
||||
{
|
||||
int m_magic;
|
||||
int m_magic = 0;
|
||||
basisu_transcoder m_transcoder;
|
||||
void *m_pFile;
|
||||
uint m_file_size;
|
||||
std::vector<uint8_t> m_file;
|
||||
|
||||
basis_file() :
|
||||
m_transcoder(g_pGlobal_codebook)
|
||||
{
|
||||
}
|
||||
basis_file(const emscripten::val& jsBuffer)
|
||||
: m_file([&]() {
|
||||
size_t byteLength = jsBuffer["byteLength"].as<size_t>();
|
||||
return std::vector<uint8_t>(byteLength);
|
||||
}()),
|
||||
m_transcoder(g_pGlobal_codebook)
|
||||
{
|
||||
unsigned int length = jsBuffer["length"].as<unsigned int>();
|
||||
emscripten::val memory = emscripten::val::module_property("HEAP8")["buffer"];
|
||||
emscripten::val memoryView = jsBuffer["constructor"].new_(memory, reinterpret_cast<uintptr_t>(m_file.data()), length);
|
||||
memoryView.call<void>("set", jsBuffer);
|
||||
|
||||
if (!m_transcoder.validate_header(m_file.data(), m_file.size())) {
|
||||
m_file.clear();
|
||||
std::cerr << "Invalid Basis header" << std::endl;
|
||||
}
|
||||
|
||||
// Initialized after validation
|
||||
m_magic = MAGIC;
|
||||
}
|
||||
|
||||
void close() {
|
||||
assert(m_magic == MAGIC);
|
||||
m_file.clear();
|
||||
}
|
||||
|
||||
uint32_t getHasAlpha() {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
basisu_image_level_info li;
|
||||
if (!m_transcoder.get_image_level_info(m_file.data(), m_file.size(), li, 0, 0))
|
||||
return 0;
|
||||
|
||||
return li.m_alpha_flag;
|
||||
}
|
||||
|
||||
uint32_t getNumImages() {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
return m_transcoder.get_total_images(m_file.data(), m_file.size());
|
||||
}
|
||||
|
||||
uint32_t getNumLevels(uint32_t image_index) {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
basisu_image_info ii;
|
||||
if (!m_transcoder.get_image_info(m_file.data(), m_file.size(), ii, image_index))
|
||||
return 0;
|
||||
|
||||
return ii.m_total_levels;
|
||||
}
|
||||
|
||||
uint32_t getImageWidth(uint32_t image_index, uint32_t level_index) {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
uint32_t orig_width, orig_height, total_blocks;
|
||||
if (!m_transcoder.get_image_level_desc(m_file.data(), m_file.size(), image_index, level_index, orig_width, orig_height, total_blocks))
|
||||
return 0;
|
||||
|
||||
return orig_width;
|
||||
}
|
||||
|
||||
uint32_t getImageHeight(uint32_t image_index, uint32_t level_index) {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
uint32_t orig_width, orig_height, total_blocks;
|
||||
if (!m_transcoder.get_image_level_desc(m_file.data(), m_file.size(), image_index, level_index, orig_width, orig_height, total_blocks))
|
||||
return 0;
|
||||
|
||||
return orig_height;
|
||||
}
|
||||
|
||||
uint32_t getImageTranscodedSizeInBytes(uint32_t image_index, uint32_t level_index, uint32_t format) {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
if (format >= cTFTotalTextureFormats)
|
||||
return 0;
|
||||
|
||||
uint32_t bytes_per_block = basis_get_bytes_per_block(static_cast<transcoder_texture_format>(format));
|
||||
|
||||
uint32_t orig_width, orig_height, total_blocks;
|
||||
if (!m_transcoder.get_image_level_desc(m_file.data(), m_file.size(), image_index, level_index, orig_width, orig_height, total_blocks))
|
||||
return 0;
|
||||
|
||||
return total_blocks * bytes_per_block;
|
||||
}
|
||||
|
||||
uint32_t startTranscoding() {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
return m_transcoder.start_transcoding(m_file.data(), m_file.size());
|
||||
}
|
||||
|
||||
uint32_t transcodeImage(const emscripten::val& dst, uint32_t image_index, uint32_t level_index, uint32_t format, uint32_t pvrtc_wrap_addressing, uint32_t get_alpha_for_opaque_formats) {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
if (format >= cTFTotalTextureFormats)
|
||||
return 0;
|
||||
|
||||
uint32_t bytes_per_block = basis_get_bytes_per_block(static_cast<transcoder_texture_format>(format));
|
||||
|
||||
uint32_t orig_width, orig_height, total_blocks;
|
||||
if (!m_transcoder.get_image_level_desc(m_file.data(), m_file.size(), image_index, level_index, orig_width, orig_height, total_blocks))
|
||||
return 0;
|
||||
|
||||
uint32_t required_size = total_blocks * bytes_per_block;
|
||||
|
||||
std::vector<uint8_t> dst_data(required_size);
|
||||
|
||||
uint32_t status = m_transcoder.transcode_image_level(
|
||||
m_file.data(), m_file.size(), image_index, level_index,
|
||||
dst_data.data(), dst_data.size() / bytes_per_block,
|
||||
static_cast<basist::transcoder_texture_format>(format),
|
||||
(
|
||||
(pvrtc_wrap_addressing ? basisu_transcoder::cDecodeFlagsPVRTCWrapAddressing : 0) |
|
||||
(get_alpha_for_opaque_formats ? basisu_transcoder::cDecodeFlagsTranscodeAlphaDataToOpaqueFormats : 0)
|
||||
));
|
||||
|
||||
emscripten::val memory = emscripten::val::module_property("HEAP8")["buffer"];
|
||||
emscripten::val memoryView = emscripten::val::global("Uint8Array").new_(memory, reinterpret_cast<uintptr_t>(dst_data.data()), dst_data.size());
|
||||
|
||||
dst.call<void>("set", memoryView);
|
||||
return status;
|
||||
}
|
||||
};
|
||||
|
||||
void *basis_open(void *src, uint src_size)
|
||||
{
|
||||
if ((!src) || (!src_size))
|
||||
return nullptr;
|
||||
|
||||
basis_file *f = new basis_file;
|
||||
f->m_pFile = src;
|
||||
f->m_file_size = src_size;
|
||||
|
||||
if (!f->m_transcoder.validate_header(f->m_pFile, f->m_file_size))
|
||||
{
|
||||
delete f;
|
||||
return nullptr;
|
||||
}
|
||||
f->m_magic = MAGIC;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void basis_close(void *h)
|
||||
{
|
||||
basis_file *f = static_cast<basis_file *>(h);
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
assert(f->m_magic == MAGIC);
|
||||
if (f->m_magic != MAGIC)
|
||||
return;
|
||||
|
||||
delete f;
|
||||
}
|
||||
|
||||
uint basis_get_has_alpha(void *h)
|
||||
{
|
||||
basis_file *f = static_cast<basis_file *>(h);
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
assert(f->m_magic == MAGIC);
|
||||
if (f->m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
basisu_image_level_info li;
|
||||
|
||||
if (!f->m_transcoder.get_image_level_info(f->m_pFile, f->m_file_size, li, 0, 0))
|
||||
return 0;
|
||||
|
||||
return li.m_alpha_flag;
|
||||
}
|
||||
|
||||
uint basis_get_num_images(void *h)
|
||||
{
|
||||
basis_file *f = static_cast<basis_file *>(h);
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
assert(f->m_magic == MAGIC);
|
||||
if (f->m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
return f->m_transcoder.get_total_images(f->m_pFile, f->m_file_size);
|
||||
}
|
||||
|
||||
uint basis_get_num_levels(void *h, uint image_index)
|
||||
{
|
||||
basis_file *f = static_cast<basis_file *>(h);
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
assert(f->m_magic == MAGIC);
|
||||
if (f->m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
basisu_image_info ii;
|
||||
|
||||
if (!f->m_transcoder.get_image_info(f->m_pFile, f->m_file_size, ii, image_index))
|
||||
return 0;
|
||||
|
||||
return ii.m_total_levels;
|
||||
}
|
||||
|
||||
uint basis_get_image_width(void *h, uint image_index, uint level_index)
|
||||
{
|
||||
basis_file *f = static_cast<basis_file *>(h);
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
assert(f->m_magic == MAGIC);
|
||||
if (f->m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
uint orig_width, orig_height, total_blocks;
|
||||
if (!f->m_transcoder.get_image_level_desc(f->m_pFile, f->m_file_size, image_index, level_index, orig_width, orig_height, total_blocks))
|
||||
return 0;
|
||||
|
||||
return orig_width;
|
||||
}
|
||||
|
||||
uint basis_get_image_height(void *h, uint image_index, uint level_index)
|
||||
{
|
||||
basis_file *f = static_cast<basis_file *>(h);
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
assert(f->m_magic == MAGIC);
|
||||
if (f->m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
uint orig_width, orig_height, total_blocks;
|
||||
if (!f->m_transcoder.get_image_level_desc(f->m_pFile, f->m_file_size, image_index, level_index, orig_width, orig_height, total_blocks))
|
||||
return 0;
|
||||
|
||||
return orig_height;
|
||||
}
|
||||
|
||||
uint basis_get_image_transcoded_size_in_bytes(void *h, uint image_index, uint level_index, uint format)
|
||||
{
|
||||
basis_file *f = static_cast<basis_file *>(h);
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
assert(f->m_magic == MAGIC);
|
||||
if (f->m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
if (format >= cTFTotalTextureFormats)
|
||||
return 0;
|
||||
|
||||
uint bytes_per_block = basis_get_bytes_per_block((transcoder_texture_format)format);
|
||||
|
||||
uint orig_width, orig_height, total_blocks;
|
||||
if (!f->m_transcoder.get_image_level_desc(f->m_pFile, f->m_file_size, image_index, level_index, orig_width, orig_height, total_blocks))
|
||||
return 0;
|
||||
|
||||
return total_blocks * bytes_per_block;
|
||||
}
|
||||
|
||||
uint basis_start_transcoding(void *h)
|
||||
{
|
||||
basis_file *f = static_cast<basis_file *>(h);
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
assert(f->m_magic == MAGIC);
|
||||
if (f->m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
return f->m_transcoder.start_transcoding(f->m_pFile, f->m_file_size);
|
||||
}
|
||||
|
||||
uint basis_transcode_image(void *h, void *dst, uint dst_size_in_bytes,
|
||||
uint image_index, uint level_index, uint format,
|
||||
uint pvrtc_wrap_addressing, uint get_alpha_for_opaque_formats)
|
||||
{
|
||||
basis_file *f = static_cast<basis_file *>(h);
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
assert(f->m_magic == MAGIC);
|
||||
if (f->m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
if (format >= cTFTotalTextureFormats)
|
||||
return 0;
|
||||
|
||||
uint bytes_per_block = basis_get_bytes_per_block((transcoder_texture_format)format);
|
||||
|
||||
return f->m_transcoder.transcode_image_level(f->m_pFile, f->m_file_size, image_index, level_index,
|
||||
dst, dst_size_in_bytes / bytes_per_block,
|
||||
(basist::transcoder_texture_format)format,
|
||||
(pvrtc_wrap_addressing ? basisu_transcoder::cDecodeFlagsPVRTCWrapAddressing : 0) | (get_alpha_for_opaque_formats ? basisu_transcoder::cDecodeFlagsTranscodeAlphaDataToOpaqueFormats : 0));
|
||||
EMSCRIPTEN_BINDINGS(basis_transcoder) {
|
||||
|
||||
function("initializeBasis", &basis_init);
|
||||
|
||||
class_<basis_file>("BasisFile")
|
||||
.constructor<const emscripten::val&>()
|
||||
.function("close", optional_override([](basis_file& self) {
|
||||
return self.close();
|
||||
}))
|
||||
.function("getHasAlpha", optional_override([](basis_file& self) {
|
||||
return self.getHasAlpha();
|
||||
}))
|
||||
.function("getNumImages", optional_override([](basis_file& self) {
|
||||
return self.getNumImages();
|
||||
}))
|
||||
.function("getNumLevels", optional_override([](basis_file& self, uint32_t imageIndex) {
|
||||
return self.getNumLevels(imageIndex);
|
||||
}))
|
||||
.function("getImageWidth", optional_override([](basis_file& self, uint32_t imageIndex, uint32_t levelIndex) {
|
||||
return self.getImageWidth(imageIndex, levelIndex);
|
||||
}))
|
||||
.function("getImageHeight", optional_override([](basis_file& self, uint32_t imageIndex, uint32_t levelIndex) {
|
||||
return self.getImageHeight(imageIndex, levelIndex);
|
||||
}))
|
||||
.function("getImageTranscodedSizeInBytes", optional_override([](basis_file& self, uint32_t imageIndex, uint32_t levelIndex, uint32_t format) {
|
||||
return self.getImageTranscodedSizeInBytes(imageIndex, levelIndex, format);
|
||||
}))
|
||||
.function("startTranscoding", optional_override([](basis_file& self) {
|
||||
return self.startTranscoding();
|
||||
}))
|
||||
.function("transcodeImage", optional_override([](basis_file& self, const emscripten::val& dst, uint32_t imageIndex, uint32_t levelIndex, uint32_t format, uint32_t pvrtcWrapAddressing, uint32_t getAlphaForOpaqueFormats) {
|
||||
return self.transcodeImage(dst, imageIndex, levelIndex, format, pvrtcWrapAddressing, getAlphaForOpaqueFormats);
|
||||
}))
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
@REM -O0 -s ASSERTIONS=1 -s DEMANGLE_SUPPORT=1
|
||||
@REM -O2 -s ASSERTIONS=0
|
||||
emcc -s EXPORTED_FUNCTIONS="['allocate', '_malloc', '_free', '_basis_init','_basis_open','_basis_close','_basis_get_has_alpha','_basis_get_num_images','_basis_get_num_levels','_basis_get_image_width','_basis_get_image_height','_basis_get_image_transcoded_size_in_bytes','_basis_transcode_image','_basis_start_transcoding']" -o basis.js ../transcoder/basisu_transcoder.cpp basis_wrappers.cpp -s TOTAL_MEMORY=60000000 -O2 -s ASSERTIONS=0 -I ../transcoder
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# rg - I haven't tested this shell script yet (I use build.bat on Windows)
|
||||
|
||||
emcc \
|
||||
-s EXPORTED_FUNCTIONS="['allocate', '_malloc', '_free', '_basis_init','_basis_open','_basis_close','_basis_get_has_alpha','_basis_get_num_images','_basis_get_num_levels','_basis_get_image_width','_basis_get_image_height','_basis_get_image_transcoded_size_in_bytes','_basis_transcode_image','_basis_start_transcoding']" \
|
||||
-s TOTAL_MEMORY=640MB -O2 -s ASSERTIONS=0 -I ../transcoder \
|
||||
-o basis.js \
|
||||
../transcoder/basisu_transcoder.cpp basis_wrappers.cpp && \
|
||||
chmod -R a+rX .
|
||||
@@ -5,7 +5,7 @@
|
||||
<script src="GLTFLoader.js"></script>
|
||||
<script src="BasisTextureLoader.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@v0.104.0/examples/js/controls/OrbitControls.js"></script>
|
||||
<script src="./wasm/build/basis_transcoder.js"></script>
|
||||
<script src="../wasm/build/basis_transcoder.js"></script>
|
||||
<style>
|
||||
html, body { width:100%; height:100%; margin:0; padding:0; }
|
||||
canvas { display:block; }
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
// basis_wrappers.cpp - Simple C-style wrappers to the C++ transcoder for WebGL use.
|
||||
#include "basisu_transcoder.h"
|
||||
#include <emscripten/bind.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace emscripten;
|
||||
using namespace basist;
|
||||
|
||||
static basist::etc1_global_selector_codebook *g_pGlobal_codebook;
|
||||
|
||||
void basis_init()
|
||||
{
|
||||
basisu_transcoder_init();
|
||||
|
||||
if (!g_pGlobal_codebook)
|
||||
g_pGlobal_codebook = new basist::etc1_global_selector_codebook(g_global_selector_cb_size, g_global_selector_cb);
|
||||
}
|
||||
|
||||
#define MAGIC 0xDEADBEE1
|
||||
|
||||
struct basis_file
|
||||
{
|
||||
int m_magic = 0;
|
||||
basisu_transcoder m_transcoder;
|
||||
std::vector<uint8_t> m_file;
|
||||
|
||||
basis_file(const emscripten::val& jsBuffer)
|
||||
: m_file([&]() {
|
||||
size_t byteLength = jsBuffer["byteLength"].as<size_t>();
|
||||
return std::vector<uint8_t>(byteLength);
|
||||
}()),
|
||||
m_transcoder(g_pGlobal_codebook)
|
||||
{
|
||||
unsigned int length = jsBuffer["length"].as<unsigned int>();
|
||||
emscripten::val memory = emscripten::val::module_property("HEAP8")["buffer"];
|
||||
emscripten::val memoryView = jsBuffer["constructor"].new_(memory, reinterpret_cast<uintptr_t>(m_file.data()), length);
|
||||
memoryView.call<void>("set", jsBuffer);
|
||||
|
||||
if (!m_transcoder.validate_header(m_file.data(), m_file.size())) {
|
||||
m_file.clear();
|
||||
std::cerr << "Invalid Basis header" << std::endl;
|
||||
}
|
||||
|
||||
// Initialized after validation
|
||||
m_magic = MAGIC;
|
||||
}
|
||||
|
||||
void close() {
|
||||
assert(m_magic == MAGIC);
|
||||
m_file.clear();
|
||||
}
|
||||
|
||||
uint32_t getHasAlpha() {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
basisu_image_level_info li;
|
||||
if (!m_transcoder.get_image_level_info(m_file.data(), m_file.size(), li, 0, 0))
|
||||
return 0;
|
||||
|
||||
return li.m_alpha_flag;
|
||||
}
|
||||
|
||||
uint32_t getNumImages() {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
return m_transcoder.get_total_images(m_file.data(), m_file.size());
|
||||
}
|
||||
|
||||
uint32_t getNumLevels(uint32_t image_index) {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
basisu_image_info ii;
|
||||
if (!m_transcoder.get_image_info(m_file.data(), m_file.size(), ii, image_index))
|
||||
return 0;
|
||||
|
||||
return ii.m_total_levels;
|
||||
}
|
||||
|
||||
uint32_t getImageWidth(uint32_t image_index, uint32_t level_index) {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
uint32_t orig_width, orig_height, total_blocks;
|
||||
if (!m_transcoder.get_image_level_desc(m_file.data(), m_file.size(), image_index, level_index, orig_width, orig_height, total_blocks))
|
||||
return 0;
|
||||
|
||||
return orig_width;
|
||||
}
|
||||
|
||||
uint32_t getImageHeight(uint32_t image_index, uint32_t level_index) {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
uint32_t orig_width, orig_height, total_blocks;
|
||||
if (!m_transcoder.get_image_level_desc(m_file.data(), m_file.size(), image_index, level_index, orig_width, orig_height, total_blocks))
|
||||
return 0;
|
||||
|
||||
return orig_height;
|
||||
}
|
||||
|
||||
uint32_t getImageTranscodedSizeInBytes(uint32_t image_index, uint32_t level_index, uint32_t format) {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
if (format >= cTFTotalTextureFormats)
|
||||
return 0;
|
||||
|
||||
uint32_t bytes_per_block = basis_get_bytes_per_block(static_cast<transcoder_texture_format>(format));
|
||||
|
||||
uint32_t orig_width, orig_height, total_blocks;
|
||||
if (!m_transcoder.get_image_level_desc(m_file.data(), m_file.size(), image_index, level_index, orig_width, orig_height, total_blocks))
|
||||
return 0;
|
||||
|
||||
return total_blocks * bytes_per_block;
|
||||
}
|
||||
|
||||
uint32_t startTranscoding() {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
return m_transcoder.start_transcoding(m_file.data(), m_file.size());
|
||||
}
|
||||
|
||||
uint32_t transcodeImage(const emscripten::val& dst, uint32_t image_index, uint32_t level_index, uint32_t format, uint32_t pvrtc_wrap_addressing, uint32_t get_alpha_for_opaque_formats) {
|
||||
assert(m_magic == MAGIC);
|
||||
if (m_magic != MAGIC)
|
||||
return 0;
|
||||
|
||||
if (format >= cTFTotalTextureFormats)
|
||||
return 0;
|
||||
|
||||
uint32_t bytes_per_block = basis_get_bytes_per_block(static_cast<transcoder_texture_format>(format));
|
||||
|
||||
uint32_t orig_width, orig_height, total_blocks;
|
||||
if (!m_transcoder.get_image_level_desc(m_file.data(), m_file.size(), image_index, level_index, orig_width, orig_height, total_blocks))
|
||||
return 0;
|
||||
|
||||
uint32_t required_size = total_blocks * bytes_per_block;
|
||||
|
||||
std::vector<uint8_t> dst_data(required_size);
|
||||
|
||||
uint32_t status = m_transcoder.transcode_image_level(
|
||||
m_file.data(), m_file.size(), image_index, level_index,
|
||||
dst_data.data(), dst_data.size() / bytes_per_block,
|
||||
static_cast<basist::transcoder_texture_format>(format),
|
||||
(
|
||||
(pvrtc_wrap_addressing ? basisu_transcoder::cDecodeFlagsPVRTCWrapAddressing : 0) |
|
||||
(get_alpha_for_opaque_formats ? basisu_transcoder::cDecodeFlagsTranscodeAlphaDataToOpaqueFormats : 0)
|
||||
));
|
||||
|
||||
emscripten::val memory = emscripten::val::module_property("HEAP8")["buffer"];
|
||||
emscripten::val memoryView = emscripten::val::global("Uint8Array").new_(memory, reinterpret_cast<uintptr_t>(dst_data.data()), dst_data.size());
|
||||
|
||||
dst.call<void>("set", memoryView);
|
||||
return status;
|
||||
}
|
||||
};
|
||||
|
||||
EMSCRIPTEN_BINDINGS(basis_transcoder) {
|
||||
|
||||
function("initializeBasis", &basis_init);
|
||||
|
||||
class_<basis_file>("BasisFile")
|
||||
.constructor<const emscripten::val&>()
|
||||
.function("close", optional_override([](basis_file& self) {
|
||||
return self.close();
|
||||
}))
|
||||
.function("getHasAlpha", optional_override([](basis_file& self) {
|
||||
return self.getHasAlpha();
|
||||
}))
|
||||
.function("getNumImages", optional_override([](basis_file& self) {
|
||||
return self.getNumImages();
|
||||
}))
|
||||
.function("getNumLevels", optional_override([](basis_file& self, uint32_t imageIndex) {
|
||||
return self.getNumLevels(imageIndex);
|
||||
}))
|
||||
.function("getImageWidth", optional_override([](basis_file& self, uint32_t imageIndex, uint32_t levelIndex) {
|
||||
return self.getImageWidth(imageIndex, levelIndex);
|
||||
}))
|
||||
.function("getImageHeight", optional_override([](basis_file& self, uint32_t imageIndex, uint32_t levelIndex) {
|
||||
return self.getImageHeight(imageIndex, levelIndex);
|
||||
}))
|
||||
.function("getImageTranscodedSizeInBytes", optional_override([](basis_file& self, uint32_t imageIndex, uint32_t levelIndex, uint32_t format) {
|
||||
return self.getImageTranscodedSizeInBytes(imageIndex, levelIndex, format);
|
||||
}))
|
||||
.function("startTranscoding", optional_override([](basis_file& self) {
|
||||
return self.startTranscoding();
|
||||
}))
|
||||
.function("transcodeImage", optional_override([](basis_file& self, const emscripten::val& dst, uint32_t imageIndex, uint32_t levelIndex, uint32_t format, uint32_t pvrtcWrapAddressing, uint32_t getAlphaForOpaqueFormats) {
|
||||
return self.transcodeImage(dst, imageIndex, levelIndex, format, pvrtcWrapAddressing, getAlphaForOpaqueFormats);
|
||||
}))
|
||||
;
|
||||
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -2,7 +2,7 @@
|
||||
<head>
|
||||
<script src="renderer.js"></script>
|
||||
<script src="dxt-to-rgb565.js"></script>
|
||||
<script src="./gltf-demo/wasm/build/basis_transcoder.js"></script>
|
||||
<script src="./wasm/build/basis_transcoder.js"></script>
|
||||
<script type="text/javascript">
|
||||
function log(s) {
|
||||
var div = document.createElement('div');
|
||||
|
||||
@@ -6,11 +6,11 @@ if (EMSCRIPTEN)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
add_executable(basis_transcoder.js
|
||||
../../../transcoder/basisu_transcoder.cpp
|
||||
basis_wrappers.cpp
|
||||
../../transcoder/basisu_transcoder.cpp
|
||||
../basis_wrappers.cpp
|
||||
)
|
||||
|
||||
target_include_directories(basis_transcoder.js PRIVATE ../../../transcoder)
|
||||
target_include_directories(basis_transcoder.js PRIVATE ../../transcoder)
|
||||
|
||||
set_target_properties(basis_transcoder.js PROPERTIES
|
||||
OUTPUT_NAME "basis_transcoder"
|
||||
Reference in New Issue
Block a user