mirror of
https://github.com/BinomialLLC/basis_universal.git
synced 2026-06-12 10:33:51 +00:00
206 lines
6.8 KiB
C++
206 lines
6.8 KiB
C++
// 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);
|
|
}))
|
|
;
|
|
|
|
}
|