// basis_wrappers.cpp - Simple C-style wrappers to the C++ transcoder for WebGL use. #include "basisu_transcoder.h" #include #include 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 m_file; basis_file(const emscripten::val& jsBuffer) : m_file([&]() { size_t byteLength = jsBuffer["byteLength"].as(); return std::vector(byteLength); }()), m_transcoder(g_pGlobal_codebook) { unsigned int length = jsBuffer["length"].as(); emscripten::val memory = emscripten::val::module_property("HEAP8")["buffer"]; emscripten::val memoryView = jsBuffer["constructor"].new_(memory, reinterpret_cast(m_file.data()), length); memoryView.call("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(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(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 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(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(dst_data.data()), dst_data.size()); dst.call("set", memoryView); return status; } }; EMSCRIPTEN_BINDINGS(basis_transcoder) { function("initializeBasis", &basis_init); class_("BasisFile") .constructor() .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); })) ; }