mirror of
https://github.com/BinomialLLC/basis_universal.git
synced 2026-06-08 08:33:53 +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
|
### 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.
|
See more details [here](webgl/README.md).
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
### Transcoder details
|
### 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)
|
* DTX (BC1)
|
||||||
* Tested in Chrome (Linux and macOS) and Firefox (macOS).
|
* Tested in Chrome (Linux and macOS) and Firefox (macOS).
|
||||||
* ETC1
|
* 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)
|
* PVRTC (COMPRESSED_RGB_PVRTC_4BPPV1_IMG)
|
||||||
* Tested in Chrome and Safari on iOS iPhone 6 Plus.
|
* 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
|
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.
|
extension that is currently in development.
|
||||||
|
|
||||||
|
Both demos requires WebAssembly and WebGL support.
|
||||||
|
|
||||||
## Testing locally
|
## 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:
|
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:
|
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
|
```shell
|
||||||
cd webgl/gltf-demo/wasm/build/
|
cd webgl/wasm/build/
|
||||||
emcmake cmake ../
|
emcmake cmake ../
|
||||||
make
|
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 "basisu_transcoder.h"
|
||||||
|
#include <emscripten/bind.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace emscripten;
|
||||||
using namespace basist;
|
using namespace basist;
|
||||||
|
|
||||||
static basist::etc1_global_selector_codebook *g_pGlobal_codebook;
|
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()
|
void basis_init()
|
||||||
{
|
{
|
||||||
basisu_transcoder_init();
|
basisu_transcoder_init();
|
||||||
|
|
||||||
if (!g_pGlobal_codebook)
|
if (!g_pGlobal_codebook)
|
||||||
g_pGlobal_codebook = new basist::etc1_global_selector_codebook(g_global_selector_cb_size, g_global_selector_cb);
|
g_pGlobal_codebook = new basist::etc1_global_selector_codebook(g_global_selector_cb_size, g_global_selector_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAGIC 0xDEADBEE1
|
#define MAGIC 0xDEADBEE1
|
||||||
|
|
||||||
struct basis_file
|
struct basis_file
|
||||||
{
|
{
|
||||||
int m_magic;
|
int m_magic = 0;
|
||||||
basisu_transcoder m_transcoder;
|
basisu_transcoder m_transcoder;
|
||||||
void *m_pFile;
|
std::vector<uint8_t> m_file;
|
||||||
uint m_file_size;
|
|
||||||
|
|
||||||
basis_file() :
|
basis_file(const emscripten::val& jsBuffer)
|
||||||
m_transcoder(g_pGlobal_codebook)
|
: 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)
|
EMSCRIPTEN_BINDINGS(basis_transcoder) {
|
||||||
{
|
|
||||||
if ((!src) || (!src_size))
|
function("initializeBasis", &basis_init);
|
||||||
return nullptr;
|
|
||||||
|
class_<basis_file>("BasisFile")
|
||||||
basis_file *f = new basis_file;
|
.constructor<const emscripten::val&>()
|
||||||
f->m_pFile = src;
|
.function("close", optional_override([](basis_file& self) {
|
||||||
f->m_file_size = src_size;
|
return self.close();
|
||||||
|
}))
|
||||||
if (!f->m_transcoder.validate_header(f->m_pFile, f->m_file_size))
|
.function("getHasAlpha", optional_override([](basis_file& self) {
|
||||||
{
|
return self.getHasAlpha();
|
||||||
delete f;
|
}))
|
||||||
return nullptr;
|
.function("getNumImages", optional_override([](basis_file& self) {
|
||||||
}
|
return self.getNumImages();
|
||||||
f->m_magic = MAGIC;
|
}))
|
||||||
|
.function("getNumLevels", optional_override([](basis_file& self, uint32_t imageIndex) {
|
||||||
return f;
|
return self.getNumLevels(imageIndex);
|
||||||
}
|
}))
|
||||||
|
.function("getImageWidth", optional_override([](basis_file& self, uint32_t imageIndex, uint32_t levelIndex) {
|
||||||
void basis_close(void *h)
|
return self.getImageWidth(imageIndex, levelIndex);
|
||||||
{
|
}))
|
||||||
basis_file *f = static_cast<basis_file *>(h);
|
.function("getImageHeight", optional_override([](basis_file& self, uint32_t imageIndex, uint32_t levelIndex) {
|
||||||
if (!f)
|
return self.getImageHeight(imageIndex, levelIndex);
|
||||||
return;
|
}))
|
||||||
|
.function("getImageTranscodedSizeInBytes", optional_override([](basis_file& self, uint32_t imageIndex, uint32_t levelIndex, uint32_t format) {
|
||||||
assert(f->m_magic == MAGIC);
|
return self.getImageTranscodedSizeInBytes(imageIndex, levelIndex, format);
|
||||||
if (f->m_magic != MAGIC)
|
}))
|
||||||
return;
|
.function("startTranscoding", optional_override([](basis_file& self) {
|
||||||
|
return self.startTranscoding();
|
||||||
delete f;
|
}))
|
||||||
}
|
.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);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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="GLTFLoader.js"></script>
|
||||||
<script src="BasisTextureLoader.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="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>
|
<style>
|
||||||
html, body { width:100%; height:100%; margin:0; padding:0; }
|
html, body { width:100%; height:100%; margin:0; padding:0; }
|
||||||
canvas { display:block; }
|
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>
|
<head>
|
||||||
<script src="renderer.js"></script>
|
<script src="renderer.js"></script>
|
||||||
<script src="dxt-to-rgb565.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">
|
<script type="text/javascript">
|
||||||
function log(s) {
|
function log(s) {
|
||||||
var div = document.createElement('div');
|
var div = document.createElement('div');
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ if (EMSCRIPTEN)
|
|||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
|
||||||
add_executable(basis_transcoder.js
|
add_executable(basis_transcoder.js
|
||||||
../../../transcoder/basisu_transcoder.cpp
|
../../transcoder/basisu_transcoder.cpp
|
||||||
basis_wrappers.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
|
set_target_properties(basis_transcoder.js PROPERTIES
|
||||||
OUTPUT_NAME "basis_transcoder"
|
OUTPUT_NAME "basis_transcoder"
|
||||||
Reference in New Issue
Block a user