// SPDX-FileCopyrightText: 2023 Unity Technologies and the KTX for Unity authors
// SPDX-License-Identifier: Apache-2.0
using System.Runtime.InteropServices;
using System;
using UnityEngine;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine.Profiling;
namespace KtxUnity
{
// Source: basisu_transcoder.h -> basist::basis_texture_type
enum BasisUniversalTextureType
{
///
/// An arbitrary array of 2D RGB or RGBA images with optional mipmaps,
/// array size = # images, each image may have a different resolution
/// and # of mipmap levels
///
Image2D = 0,
///
/// An array of 2D RGB or RGBA images with optional mipmaps,
/// array size = # images, each image has the same resolution and
/// mipmap levels
///
Image2DArray = 1,
///
/// An array of cubemap levels,
/// total # of images must be dividable by 6,
/// in X+, X-, Y+, Y-, Z+, Z- order, with optional mipmaps
///
CubemapArray = 2,
///
/// An array of 2D video frames, with optional mipmaps,
/// # frames = # images, each image has the same resolution and # of
/// mipmap levels
///
VideoFrames = 3,
///
/// A 3D texture with optional mipmaps, Z dimension = # images,
/// each image has the same resolution and # of mipmap levels
///
Volume = 4,
}
class BasisUniversalTranscoderInstance
{
public IntPtr nativeReference;
public BasisUniversalTranscoderInstance(IntPtr nativeReference)
{
this.nativeReference = nativeReference;
}
public unsafe bool Open(NativeSlice data)
{
void* src = data.GetUnsafeReadOnlyPtr();
bool success = ktx_basisu_open_basis(nativeReference, src, data.Length);
#if DEBUG
if(!success) {
Debug.LogError("Couldn't validate BasisU header!");
}
#endif
return success;
}
public MetaData LoadMetaData()
{
Profiler.BeginSample("LoadMetaData");
MetaData meta = new MetaData();
meta.hasAlpha = GetHasAlpha();
var imageCount = GetImageCount();
meta.images = new ImageInfo[imageCount];
for (uint i = 0; i < imageCount; i++)
{
var ii = new ImageInfo();
var levelCount = GetLevelCount(i);
ii.levels = new LevelInfo[levelCount];
for (uint l = 0; l < levelCount; l++)
{
var li = new LevelInfo();
GetImageSize(out li.width, out li.height, i, l);
ii.levels[l] = li;
}
meta.images[i] = ii;
}
Profiler.EndSample();
return meta;
}
public void Close()
{
ktx_basisu_close_basis(nativeReference);
}
public bool GetHasAlpha()
{
return ktx_basisu_getHasAlpha(nativeReference);
}
public uint GetImageCount()
{
return ktx_basisu_getNumImages(nativeReference);
}
public uint GetLevelCount(uint imageIndex)
{
return ktx_basisu_getNumLevels(nativeReference, imageIndex);
}
public void GetImageSize(out uint width, out uint height, uint imageIndex = 0, uint levelIndex = 0)
{
width = ktx_basisu_getImageWidth(nativeReference, imageIndex, levelIndex);
height = ktx_basisu_getImageHeight(nativeReference, imageIndex, levelIndex);
}
public bool GetYFlip()
{
return !ktx_basisu_get_y_flip(nativeReference);
}
// public bool GetIsEtc1s() {
// return ktx_basisu_get_is_etc1s(nativeReference);
// }
public BasisUniversalTextureType GetTextureType()
{
return ktx_basisu_get_texture_type(nativeReference);
}
public uint GetImageTranscodedSize(uint imageIndex, uint levelIndex, TranscodeFormat format)
{
return ktx_basisu_getImageTranscodedSizeInBytes(nativeReference, imageIndex, levelIndex, (uint)format);
}
public unsafe bool Transcode(uint imageIndex, uint levelIndex, TranscodeFormat format, out byte[] transcodedData)
{
Profiler.BeginSample("BasisU.Transcode");
transcodedData = null;
if (!ktx_basisu_startTranscoding(nativeReference))
{
Profiler.EndSample();
return false;
}
var size = GetImageTranscodedSize(imageIndex, levelIndex, format);
var data = new byte[size];
bool result;
fixed (void* dst = &(data[0]))
{
result = ktx_basisu_transcodeImage(nativeReference, dst, size, imageIndex, levelIndex, (uint)format, 0, 0);
}
transcodedData = data;
Profiler.EndSample();
return result;
}
~BasisUniversalTranscoderInstance()
{
ktx_basisu_delete_basis(nativeReference);
}
[DllImport(KtxNativeInstance.ktxLibrary)]
static extern unsafe bool ktx_basisu_open_basis(IntPtr basis, void* data, int length);
[DllImport(KtxNativeInstance.ktxLibrary)]
static extern void ktx_basisu_close_basis(IntPtr basis);
[DllImport(KtxNativeInstance.ktxLibrary)]
static extern void ktx_basisu_delete_basis(IntPtr basis);
[DllImport(KtxNativeInstance.ktxLibrary)]
static extern bool ktx_basisu_getHasAlpha(IntPtr basis);
[DllImport(KtxNativeInstance.ktxLibrary)]
static extern uint ktx_basisu_getNumImages(IntPtr basis);
[DllImport(KtxNativeInstance.ktxLibrary)]
static extern uint ktx_basisu_getNumLevels(IntPtr basis, uint imageIndex);
[DllImport(KtxNativeInstance.ktxLibrary)]
static extern uint ktx_basisu_getImageWidth(IntPtr basis, uint imageIndex, uint levelIndex);
[DllImport(KtxNativeInstance.ktxLibrary)]
static extern uint ktx_basisu_getImageHeight(IntPtr basis, uint imageIndex, uint levelIndex);
[DllImport(KtxNativeInstance.ktxLibrary)]
static extern bool ktx_basisu_get_y_flip(IntPtr basis);
// [DllImport(KtxNativeInstance.ktxLibrary)]
// private static extern bool ktx_basisu_get_is_etc1s( IntPtr basis );
[DllImport(KtxNativeInstance.ktxLibrary)]
static extern BasisUniversalTextureType ktx_basisu_get_texture_type(IntPtr basis);
[DllImport(KtxNativeInstance.ktxLibrary)]
static extern uint ktx_basisu_getImageTranscodedSizeInBytes(IntPtr basis, uint imageIndex, uint levelIndex, uint format);
[DllImport(KtxNativeInstance.ktxLibrary)]
static extern bool ktx_basisu_startTranscoding(IntPtr basis);
[DllImport(KtxNativeInstance.ktxLibrary)]
static extern unsafe bool ktx_basisu_transcodeImage(IntPtr basis, void* dst, uint dstSize, uint imageIndex, uint levelIndex, uint format, uint pvrtcWrapAddressing, uint getAlphaForOpaqueFormats);
}
}