This commit is contained in:
2026-06-14 19:09:18 +01:00
parent 14bd1a9271
commit 13fa90a0e9
3958 changed files with 999286 additions and 4 deletions
@@ -0,0 +1,296 @@
// Copyright 2019 Andreas Atteneder, All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
#include <basisu_transcoder.h>
#include "basisu_c_binding.h"
#include "unused.h"
using namespace basist;
#define MAGIC 0xDEADBEE1
bool basis_file::open(const uint8_t *buffer, uint32_t newByteLength) {
m_file = buffer;
byteLength = newByteLength;
if (!m_transcoder.validate_header(buffer, newByteLength)) {
m_file = nullptr;
byteLength = 0;
return false;
}
if (!m_transcoder.get_file_info(m_file, byteLength, fileinfo))
{
return false;
}
// Initialized after validation
m_magic = MAGIC;
return true;
}
void basis_file::close() {
assert(m_magic == MAGIC);
m_file = nullptr;
byteLength = 0;
}
uint32_t basis_file::getHasAlpha() {
assert(m_magic == MAGIC);
if (m_magic != MAGIC)
return 0;
return fileinfo.m_has_alpha_slices;
}
uint32_t basis_file::getNumImages() {
assert(m_magic == MAGIC);
if (m_magic != MAGIC)
return 0;
return m_transcoder.get_total_images(m_file, byteLength);
}
uint32_t basis_file::getNumLevels(uint32_t image_index) {
assert(m_magic == MAGIC);
if (m_magic != MAGIC)
return 0;
return fileinfo.m_image_mipmap_levels[image_index];
}
uint32_t basis_file::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, byteLength,
image_index, level_index,
orig_width, orig_height,
total_blocks))
return 0;
return orig_width;
}
uint32_t basis_file::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, byteLength,
image_index, level_index,
orig_width, orig_height,
total_blocks))
return 0;
return orig_height;
}
uint32_t basis_file::getYFlip() {
assert(m_magic == MAGIC);
return fileinfo.m_y_flipped;
}
uint32_t basis_file::getIsEtc1s() {
assert(m_magic == MAGIC);
return fileinfo.m_etc1s;
}
basis_texture_type basis_file::getTextureType() {
assert(m_magic == MAGIC);
return fileinfo.m_tex_type;
}
uint32_t basis_file::getImageTranscodedSizeInBytes(uint32_t image_index, uint32_t level_index, uint32_t format) {
assert(m_magic == MAGIC);
if (m_magic != MAGIC)
return 0;
if (format >= (uint32_t) basist::transcoder_texture_format::cTFTotalTextureFormats)
return 0;
uint32_t orig_width, orig_height, total_blocks;
if (!m_transcoder.get_image_level_desc(m_file, (uint32_t)byteLength,
image_index, level_index, orig_width,
orig_height, total_blocks))
return 0;
const transcoder_texture_format transcoder_format = static_cast<transcoder_texture_format>(format);
if (basis_transcoder_format_is_uncompressed(transcoder_format))
{
// Uncompressed formats are just plain raster images.
const uint32_t bytes_per_pixel = basis_get_uncompressed_bytes_per_pixel(transcoder_format);
const uint32_t bytes_per_line = orig_width * bytes_per_pixel;
const uint32_t bytes_per_slice = bytes_per_line * orig_height;
return bytes_per_slice;
}
else
{
// Compressed formats are 2D arrays of blocks.
const uint32_t bytes_per_block = basis_get_bytes_per_block_or_pixel(transcoder_format);
if (transcoder_format == transcoder_texture_format::cTFPVRTC1_4_RGB || transcoder_format == transcoder_texture_format::cTFPVRTC1_4_RGBA)
{
// For PVRTC1, Basis only writes (or requires) total_blocks * bytes_per_block. But GL requires extra padding for very small textures:
// https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt
const uint32_t width = (orig_width + 3) & ~3;
const uint32_t height = (orig_height + 3) & ~3;
const uint32_t size_in_bytes = (std::max(8U, width) * std::max(8U, height) * 4 + 7) / 8;
return size_in_bytes;
}
return total_blocks * bytes_per_block;
}
}
uint32_t basis_file::startTranscoding() {
assert(m_magic == MAGIC);
if (m_magic != MAGIC)
return 0;
return m_transcoder.start_transcoding(m_file, byteLength);
}
uint32_t basis_file::transcodeImage(void* dst, uint32_t dst_size, 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 >= (uint32_t) basist::transcoder_texture_format::cTFTotalTextureFormats)
return 0;
const transcoder_texture_format transcoder_format = static_cast<transcoder_texture_format>(format);
uint32_t orig_width, orig_height, total_blocks;
if (!m_transcoder.get_image_level_desc(m_file, byteLength, image_index, level_index, orig_width, orig_height, total_blocks))
return 0;
uint32_t flags = get_alpha_for_opaque_formats ? cDecodeFlagsTranscodeAlphaDataToOpaqueFormats : 0;
uint32_t status;
if (basis_transcoder_format_is_uncompressed(transcoder_format))
{
MAYBE_UNUSED const uint32_t bytes_per_pixel = basis_get_uncompressed_bytes_per_pixel(transcoder_format);
MAYBE_UNUSED const uint32_t bytes_per_line = orig_width * bytes_per_pixel;
MAYBE_UNUSED const uint32_t bytes_per_slice = bytes_per_line * orig_height;
assert(bytes_per_slice <= dst_size);
status = m_transcoder.transcode_image_level(
m_file, byteLength, image_index, level_index,
dst, orig_width * orig_height,
transcoder_format,
flags,
orig_width,
nullptr,
orig_height);
}
else
{
uint32_t bytes_per_block = basis_get_bytes_per_block_or_pixel(transcoder_format);
MAYBE_UNUSED uint32_t required_size = total_blocks * bytes_per_block;
if (transcoder_format == transcoder_texture_format::cTFPVRTC1_4_RGB || transcoder_format == transcoder_texture_format::cTFPVRTC1_4_RGBA)
{
// For PVRTC1, Basis only writes (or requires) total_blocks * bytes_per_block. But GL requires extra padding for very small textures:
// https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt
// The transcoder will clear the extra bytes followed the used blocks to 0.
const uint32_t width = (orig_width + 3) & ~3;
const uint32_t height = (orig_height + 3) & ~3;
required_size = (std::max(8U, width) * std::max(8U, height) * 4 + 7) / 8;
assert(required_size >= total_blocks * bytes_per_block);
}
assert(required_size <= dst_size);
status = m_transcoder.transcode_image_level(
m_file, byteLength, image_index, level_index,
dst, dst_size / bytes_per_block,
static_cast<basist::transcoder_texture_format>(format),
flags);
}
return status;
}
extern "C" {
KTX_BASISU_API void ktx_basisu_basis_init()
{
basisu_transcoder_init();
}
#ifdef KTX_BASISU_C_BINDINGS
KTX_BASISU_API basis_file* ktx_basisu_create_basis() {
basis_file* new_basis = new basis_file();
return new_basis;
}
KTX_BASISU_API uint32_t ktx_basisu_open_basis( basis_file* basis, const uint8_t * data, uint32_t length ) {
return basis->open(data,length);
}
KTX_BASISU_API void ktx_basisu_close_basis( basis_file* basis ) {
basis->close();
}
KTX_BASISU_API void ktx_basisu_delete_basis( basis_file* basis ) {
delete basis;
}
KTX_BASISU_API uint32_t ktx_basisu_getHasAlpha( basis_file* basis ) {
assert(basis!=nullptr);
return (bool)basis->getHasAlpha();
}
KTX_BASISU_API uint32_t ktx_basisu_getNumImages( basis_file* basis ) {
return basis->getNumImages();
}
KTX_BASISU_API uint32_t ktx_basisu_getNumLevels( basis_file* basis, uint32_t image_index) {
return basis->getNumLevels(image_index);
}
KTX_BASISU_API uint32_t ktx_basisu_getImageWidth( basis_file* basis, uint32_t image_index, uint32_t level_index) {
return basis->getImageWidth(image_index,level_index);
}
KTX_BASISU_API uint32_t ktx_basisu_getImageHeight( basis_file* basis, uint32_t image_index, uint32_t level_index) {
return basis->getImageHeight(image_index,level_index);
}
KTX_BASISU_API uint32_t ktx_basisu_get_y_flip( basis_file* basis ) {
return basis->getYFlip();
}
KTX_BASISU_API uint32_t ktx_basisu_get_is_etc1s( basis_file* basis ) {
return basis->getIsEtc1s();
}
KTX_BASISU_API basis_texture_type ktx_basisu_get_texture_type( basis_file* basis ) {
return basis->getTextureType();
}
KTX_BASISU_API uint32_t ktx_basisu_getImageTranscodedSizeInBytes( basis_file* basis, uint32_t image_index, uint32_t level_index, uint32_t format) {
return basis->getImageTranscodedSizeInBytes(image_index,level_index,format);
}
KTX_BASISU_API uint32_t ktx_basisu_startTranscoding( basis_file* basis ) {
return basis->startTranscoding();
}
KTX_BASISU_API uint32_t ktx_basisu_transcodeImage( basis_file* basis, void* dst, uint32_t dst_size, uint32_t image_index, uint32_t level_index, uint32_t format, uint32_t pvrtc_wrap_addressing, uint32_t get_alpha_for_opaque_formats) {
return basis->transcodeImage(dst,dst_size,image_index,level_index,format,pvrtc_wrap_addressing,get_alpha_for_opaque_formats);
}
#endif
} // END extern "C"