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,55 @@
# Copyright 2017-2020 The Khronos Group Inc.
# SPDX-License-Identifier: Apache-2.0
set(LIB_TYPE STATIC)
# Parent scope variables set in this context are not seen in it and, if there
# is a way to explicitly reference one, I've not found it. So 2-step.
set(BASISU_CBIND_LIBTYPE ${LIB_TYPE} PARENT_SCOPE)
add_library(obj_basisu_cbind ${LIB_TYPE}
inc/basisu_c_binding.h
src/basisu_c_binding.cpp
)
# Using cxx_std_17 because VS 2022 raises a set but unused variable warning
# and pre-c++-17 there is no 'unused' attribute. equivalent.
target_compile_features(obj_basisu_cbind PUBLIC c_std_99 cxx_std_17)
# Need this to make VS correctly define __cplusplus to the std in use.
target_compile_options(
obj_basisu_cbind
PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/Zc:__cplusplus>
)
target_include_directories(
obj_basisu_cbind
PUBLIC
inc
${KTX_BASISU_INCLUDE_DIRS}
PRIVATE
$<TARGET_PROPERTY:ktx,INCLUDE_DIRECTORIES>
${PROJECT_SOURCE_DIR}/utils
)
target_compile_definitions(
obj_basisu_cbind
PUBLIC
KTX_BASISU_C_BINDINGS
PRIVATE
$<TARGET_PROPERTY:ktx,INTERFACE_COMPILE_DEFINITIONS>
# We're only using this to read .basis files.
BASISD_SUPPORT_KTX2_ZSTD=0
BASISD_SUPPORT_KTX2=0
)
if(WIN32)
target_compile_definitions(
obj_basisu_cbind
PRIVATE
$<IF:$<STREQUAL:"${LIB_TYPE}","STATIC">,KHRONOS_STATIC,KTX_BASISU_API=__declspec\(dllexport\)>
)
elseif(APPLE)
if(KTX_EMBED_BITCODE)
target_compile_options(obj_basisu_cbind PRIVATE "-fembed-bitcode")
endif()
endif()
@@ -0,0 +1,70 @@
// Copyright 2019 Andreas Atteneder, All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
#pragma once
#if defined(KHRONOS_STATIC)
#define KTX_BASISU_API
#elif defined(_WIN32)
#if !defined(KTX_BASISU_API)
#define KTX_BASISU_API __declspec(dllimport)
#endif
#elif defined(__ANDROID__)
#define KTX_BASISU_API __attribute__((visibility("default")))
#else
#define KTX_BASISU_API
#endif
#include <basisu_transcoder.h>
using namespace basist;
class basis_file
{
unsigned int m_magic = 0;
basisu_transcoder m_transcoder;
const uint8_t *m_file;
uint32_t byteLength;
basisu_file_info fileinfo;
public:
basis_file()
:
m_transcoder()
{}
bool open(const uint8_t *buffer, uint32_t newByteLength);
void close();
uint32_t getHasAlpha();
uint32_t getNumImages();
uint32_t getNumLevels(uint32_t image_index);
uint32_t getImageWidth(uint32_t image_index, uint32_t level_index);
uint32_t getImageHeight(uint32_t image_index, uint32_t level_index);
uint32_t getYFlip();
uint32_t getIsEtc1s();
basis_texture_type getTextureType();
uint32_t getImageTranscodedSizeInBytes(uint32_t image_index, uint32_t level_index, uint32_t format);
uint32_t startTranscoding();
uint32_t 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);
};
extern "C" {
KTX_BASISU_API void ktx_basisu_basis_init();
#ifdef KTX_BASISU_C_BINDINGS
KTX_BASISU_API basis_file* ktx_basisu_create_basis();
KTX_BASISU_API uint32_t ktx_basisu_open_basis( basis_file* basis, const uint8_t * data, uint32_t length );
KTX_BASISU_API void ktx_basisu_close_basis( basis_file* basis );
KTX_BASISU_API void ktx_basisu_delete_basis( basis_file* basis );
KTX_BASISU_API uint32_t ktx_basisu_getHasAlpha( basis_file* basis );
KTX_BASISU_API uint32_t ktx_basisu_getNumImages( basis_file* basis );
KTX_BASISU_API uint32_t ktx_basisu_getNumLevels( basis_file* basis, uint32_t image_index);
KTX_BASISU_API uint32_t ktx_basisu_getImageWidth( basis_file* basis, uint32_t image_index, uint32_t level_index);
KTX_BASISU_API uint32_t ktx_basisu_getImageHeight( basis_file* basis, uint32_t image_index, uint32_t level_index);
KTX_BASISU_API uint32_t ktx_basisu_get_y_flip( basis_file* basis );
KTX_BASISU_API uint32_t ktx_basisu_get_is_etc1s( basis_file* basis );
KTX_BASISU_API basis_texture_type ktx_basisu_get_texture_type( basis_file* basis );
KTX_BASISU_API uint32_t ktx_basisu_getImageTranscodedSizeInBytes( basis_file* basis, uint32_t image_index, uint32_t level_index, uint32_t format);
KTX_BASISU_API uint32_t ktx_basisu_startTranscoding( basis_file* basis );
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);
#endif
}
@@ -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"