1cc1dc7a3Sopenharmony_ci// SPDX-License-Identifier: Apache-2.0 2cc1dc7a3Sopenharmony_ci// ---------------------------------------------------------------------------- 3cc1dc7a3Sopenharmony_ci// Copyright 2011-2023 Arm Limited 4cc1dc7a3Sopenharmony_ci// 5cc1dc7a3Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); you may not 6cc1dc7a3Sopenharmony_ci// use this file except in compliance with the License. You may obtain a copy 7cc1dc7a3Sopenharmony_ci// of the License at: 8cc1dc7a3Sopenharmony_ci// 9cc1dc7a3Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 10cc1dc7a3Sopenharmony_ci// 11cc1dc7a3Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 12cc1dc7a3Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13cc1dc7a3Sopenharmony_ci// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14cc1dc7a3Sopenharmony_ci// License for the specific language governing permissions and limitations 15cc1dc7a3Sopenharmony_ci// under the License. 16cc1dc7a3Sopenharmony_ci// ---------------------------------------------------------------------------- 17cc1dc7a3Sopenharmony_ci 18cc1dc7a3Sopenharmony_ci/** 19cc1dc7a3Sopenharmony_ci * @brief Functions for loading/storing uncompressed and compressed images. 20cc1dc7a3Sopenharmony_ci */ 21cc1dc7a3Sopenharmony_ci 22cc1dc7a3Sopenharmony_ci#include <array> 23cc1dc7a3Sopenharmony_ci#include <cassert> 24cc1dc7a3Sopenharmony_ci#include <cstdio> 25cc1dc7a3Sopenharmony_ci#include <cstdlib> 26cc1dc7a3Sopenharmony_ci#include <cstring> 27cc1dc7a3Sopenharmony_ci#include <fstream> 28cc1dc7a3Sopenharmony_ci#include <iomanip> 29cc1dc7a3Sopenharmony_ci#include <sstream> 30cc1dc7a3Sopenharmony_ci 31cc1dc7a3Sopenharmony_ci#include "astcenccli_internal.h" 32cc1dc7a3Sopenharmony_ci 33cc1dc7a3Sopenharmony_ci#include "stb_image.h" 34cc1dc7a3Sopenharmony_ci#include "stb_image_write.h" 35cc1dc7a3Sopenharmony_ci#include "tinyexr.h" 36cc1dc7a3Sopenharmony_ci 37cc1dc7a3Sopenharmony_ci/** 38cc1dc7a3Sopenharmony_ci * @brief Determine the output file name to use for a sliced image write. 39cc1dc7a3Sopenharmony_ci * 40cc1dc7a3Sopenharmony_ci * @param img The source data for the image. 41cc1dc7a3Sopenharmony_ci * @param filename The base name of the file to save. 42cc1dc7a3Sopenharmony_ci * @param index The slice index to write. 43cc1dc7a3Sopenharmony_ci * 44cc1dc7a3Sopenharmony_ci * @return The file name to use when saving the file. 45cc1dc7a3Sopenharmony_ci */ 46cc1dc7a3Sopenharmony_cistatic std::string get_output_filename( 47cc1dc7a3Sopenharmony_ci const astcenc_image* img, 48cc1dc7a3Sopenharmony_ci const char* filename, 49cc1dc7a3Sopenharmony_ci unsigned int index 50cc1dc7a3Sopenharmony_ci) { 51cc1dc7a3Sopenharmony_ci if (img->dim_z <= 1) 52cc1dc7a3Sopenharmony_ci { 53cc1dc7a3Sopenharmony_ci return filename; 54cc1dc7a3Sopenharmony_ci } 55cc1dc7a3Sopenharmony_ci 56cc1dc7a3Sopenharmony_ci std::string fnmod(filename); 57cc1dc7a3Sopenharmony_ci std::string fnext = fnmod.substr(fnmod.find_last_of(".")); 58cc1dc7a3Sopenharmony_ci 59cc1dc7a3Sopenharmony_ci // Remove the extension 60cc1dc7a3Sopenharmony_ci fnmod = fnmod.erase(fnmod.length() - fnext.size()); 61cc1dc7a3Sopenharmony_ci 62cc1dc7a3Sopenharmony_ci // Insert the file index into the base name, then append the extension 63cc1dc7a3Sopenharmony_ci std::stringstream ss; 64cc1dc7a3Sopenharmony_ci ss << fnmod << "_" << std::setw(3) << std::setfill('0') << index << fnext; 65cc1dc7a3Sopenharmony_ci return ss.str(); 66cc1dc7a3Sopenharmony_ci} 67cc1dc7a3Sopenharmony_ci 68cc1dc7a3Sopenharmony_ci/* ============================================================================ 69cc1dc7a3Sopenharmony_ci Image load and store through the stb_image and tinyexr libraries 70cc1dc7a3Sopenharmony_ci============================================================================ */ 71cc1dc7a3Sopenharmony_ci 72cc1dc7a3Sopenharmony_ci/** 73cc1dc7a3Sopenharmony_ci * @brief Load a .exr image using TinyExr to provide the loader. 74cc1dc7a3Sopenharmony_ci * 75cc1dc7a3Sopenharmony_ci * @param filename The name of the file to load. 76cc1dc7a3Sopenharmony_ci * @param y_flip Should the image be vertically flipped? 77cc1dc7a3Sopenharmony_ci * @param[out] is_hdr Is this an HDR image load? Always @c true for this function. 78cc1dc7a3Sopenharmony_ci * @param[out] component_count The number of components in the data. 79cc1dc7a3Sopenharmony_ci * 80cc1dc7a3Sopenharmony_ci * @return The loaded image data in a canonical 4 channel format. 81cc1dc7a3Sopenharmony_ci */ 82cc1dc7a3Sopenharmony_cistatic astcenc_image* load_image_with_tinyexr( 83cc1dc7a3Sopenharmony_ci const char* filename, 84cc1dc7a3Sopenharmony_ci bool y_flip, 85cc1dc7a3Sopenharmony_ci bool& is_hdr, 86cc1dc7a3Sopenharmony_ci unsigned int& component_count 87cc1dc7a3Sopenharmony_ci) { 88cc1dc7a3Sopenharmony_ci int dim_x, dim_y; 89cc1dc7a3Sopenharmony_ci float* image; 90cc1dc7a3Sopenharmony_ci const char* err; 91cc1dc7a3Sopenharmony_ci 92cc1dc7a3Sopenharmony_ci int load_res = LoadEXR(&image, &dim_x, &dim_y, filename, &err); 93cc1dc7a3Sopenharmony_ci if (load_res != TINYEXR_SUCCESS) 94cc1dc7a3Sopenharmony_ci { 95cc1dc7a3Sopenharmony_ci print_error("ERROR: Failed to load image %s (%s)\n", filename, err); 96cc1dc7a3Sopenharmony_ci free(reinterpret_cast<void*>(const_cast<char*>(err))); 97cc1dc7a3Sopenharmony_ci return nullptr; 98cc1dc7a3Sopenharmony_ci } 99cc1dc7a3Sopenharmony_ci 100cc1dc7a3Sopenharmony_ci astcenc_image* res_img = astc_img_from_floatx4_array(image, dim_x, dim_y, y_flip); 101cc1dc7a3Sopenharmony_ci free(image); 102cc1dc7a3Sopenharmony_ci 103cc1dc7a3Sopenharmony_ci is_hdr = true; 104cc1dc7a3Sopenharmony_ci component_count = 4; 105cc1dc7a3Sopenharmony_ci return res_img; 106cc1dc7a3Sopenharmony_ci} 107cc1dc7a3Sopenharmony_ci 108cc1dc7a3Sopenharmony_ci/** 109cc1dc7a3Sopenharmony_ci * @brief Load an image using STBImage to provide the loader. 110cc1dc7a3Sopenharmony_ci * 111cc1dc7a3Sopenharmony_ci * @param filename The name of the file to load. 112cc1dc7a3Sopenharmony_ci * @param y_flip Should the image be vertically flipped? 113cc1dc7a3Sopenharmony_ci * @param[out] is_hdr Is this an HDR image load? 114cc1dc7a3Sopenharmony_ci * @param[out] component_count The number of components in the data. 115cc1dc7a3Sopenharmony_ci * 116cc1dc7a3Sopenharmony_ci * @return The loaded image data in a canonical 4 channel format, or @c nullptr on error. 117cc1dc7a3Sopenharmony_ci */ 118cc1dc7a3Sopenharmony_cistatic astcenc_image* load_image_with_stb( 119cc1dc7a3Sopenharmony_ci const char* filename, 120cc1dc7a3Sopenharmony_ci bool y_flip, 121cc1dc7a3Sopenharmony_ci bool& is_hdr, 122cc1dc7a3Sopenharmony_ci unsigned int& component_count 123cc1dc7a3Sopenharmony_ci) { 124cc1dc7a3Sopenharmony_ci int dim_x, dim_y; 125cc1dc7a3Sopenharmony_ci 126cc1dc7a3Sopenharmony_ci if (stbi_is_hdr(filename)) 127cc1dc7a3Sopenharmony_ci { 128cc1dc7a3Sopenharmony_ci float* data = stbi_loadf(filename, &dim_x, &dim_y, nullptr, STBI_rgb_alpha); 129cc1dc7a3Sopenharmony_ci if (data) 130cc1dc7a3Sopenharmony_ci { 131cc1dc7a3Sopenharmony_ci astcenc_image* img = astc_img_from_floatx4_array(data, dim_x, dim_y, y_flip); 132cc1dc7a3Sopenharmony_ci stbi_image_free(data); 133cc1dc7a3Sopenharmony_ci is_hdr = true; 134cc1dc7a3Sopenharmony_ci component_count = 4; 135cc1dc7a3Sopenharmony_ci return img; 136cc1dc7a3Sopenharmony_ci } 137cc1dc7a3Sopenharmony_ci } 138cc1dc7a3Sopenharmony_ci else 139cc1dc7a3Sopenharmony_ci { 140cc1dc7a3Sopenharmony_ci uint8_t* data = stbi_load(filename, &dim_x, &dim_y, nullptr, STBI_rgb_alpha); 141cc1dc7a3Sopenharmony_ci if (data) 142cc1dc7a3Sopenharmony_ci { 143cc1dc7a3Sopenharmony_ci astcenc_image* img = astc_img_from_unorm8x4_array(data, dim_x, dim_y, y_flip); 144cc1dc7a3Sopenharmony_ci stbi_image_free(data); 145cc1dc7a3Sopenharmony_ci is_hdr = false; 146cc1dc7a3Sopenharmony_ci component_count = 4; 147cc1dc7a3Sopenharmony_ci return img; 148cc1dc7a3Sopenharmony_ci } 149cc1dc7a3Sopenharmony_ci } 150cc1dc7a3Sopenharmony_ci 151cc1dc7a3Sopenharmony_ci print_error("ERROR: Failed to load image %s (%s)\n", filename, stbi_failure_reason()); 152cc1dc7a3Sopenharmony_ci return nullptr; 153cc1dc7a3Sopenharmony_ci} 154cc1dc7a3Sopenharmony_ci 155cc1dc7a3Sopenharmony_ci/** 156cc1dc7a3Sopenharmony_ci * @brief Save an EXR image using TinyExr to provide the store routine. 157cc1dc7a3Sopenharmony_ci * 158cc1dc7a3Sopenharmony_ci * @param img The source data for the image. 159cc1dc7a3Sopenharmony_ci * @param filename The name of the file to save. 160cc1dc7a3Sopenharmony_ci * @param y_flip Should the image be vertically flipped? 161cc1dc7a3Sopenharmony_ci * 162cc1dc7a3Sopenharmony_ci * @return @c true if the image saved OK, @c false on error. 163cc1dc7a3Sopenharmony_ci */ 164cc1dc7a3Sopenharmony_cistatic bool store_exr_image_with_tinyexr( 165cc1dc7a3Sopenharmony_ci const astcenc_image* img, 166cc1dc7a3Sopenharmony_ci const char* filename, 167cc1dc7a3Sopenharmony_ci int y_flip 168cc1dc7a3Sopenharmony_ci) { 169cc1dc7a3Sopenharmony_ci int res { 0 }; 170cc1dc7a3Sopenharmony_ci 171cc1dc7a3Sopenharmony_ci for (unsigned int i = 0; i < img->dim_z; i++) 172cc1dc7a3Sopenharmony_ci { 173cc1dc7a3Sopenharmony_ci std::string fnmod = get_output_filename(img, filename, i); 174cc1dc7a3Sopenharmony_ci float* buf = floatx4_array_from_astc_img(img, y_flip, i); 175cc1dc7a3Sopenharmony_ci 176cc1dc7a3Sopenharmony_ci res = SaveEXR(buf, img->dim_x, img->dim_y, 4, 1, fnmod.c_str(), nullptr); 177cc1dc7a3Sopenharmony_ci delete[] buf; 178cc1dc7a3Sopenharmony_ci if (res < 0) 179cc1dc7a3Sopenharmony_ci { 180cc1dc7a3Sopenharmony_ci break; 181cc1dc7a3Sopenharmony_ci } 182cc1dc7a3Sopenharmony_ci } 183cc1dc7a3Sopenharmony_ci 184cc1dc7a3Sopenharmony_ci return res >= 0; 185cc1dc7a3Sopenharmony_ci} 186cc1dc7a3Sopenharmony_ci 187cc1dc7a3Sopenharmony_ci/** 188cc1dc7a3Sopenharmony_ci * @brief Save a PNG image using STBImageWrite to provide the store routine. 189cc1dc7a3Sopenharmony_ci * 190cc1dc7a3Sopenharmony_ci * @param img The source data for the image. 191cc1dc7a3Sopenharmony_ci * @param filename The name of the file to save. 192cc1dc7a3Sopenharmony_ci * @param y_flip Should the image be vertically flipped? 193cc1dc7a3Sopenharmony_ci * 194cc1dc7a3Sopenharmony_ci * @return @c true if the image saved OK, @c false on error. 195cc1dc7a3Sopenharmony_ci */ 196cc1dc7a3Sopenharmony_cistatic bool store_png_image_with_stb( 197cc1dc7a3Sopenharmony_ci const astcenc_image* img, 198cc1dc7a3Sopenharmony_ci const char* filename, 199cc1dc7a3Sopenharmony_ci int y_flip 200cc1dc7a3Sopenharmony_ci) { 201cc1dc7a3Sopenharmony_ci int res { 0 }; 202cc1dc7a3Sopenharmony_ci 203cc1dc7a3Sopenharmony_ci assert(img->data_type == ASTCENC_TYPE_U8); 204cc1dc7a3Sopenharmony_ci 205cc1dc7a3Sopenharmony_ci for (unsigned int i = 0; i < img->dim_z; i++) 206cc1dc7a3Sopenharmony_ci { 207cc1dc7a3Sopenharmony_ci std::string fnmod = get_output_filename(img, filename, i); 208cc1dc7a3Sopenharmony_ci uint8_t* buf = reinterpret_cast<uint8_t*>(img->data[i]); 209cc1dc7a3Sopenharmony_ci 210cc1dc7a3Sopenharmony_ci stbi_flip_vertically_on_write(y_flip); 211cc1dc7a3Sopenharmony_ci res = stbi_write_png(fnmod.c_str(), img->dim_x, img->dim_y, 4, buf, img->dim_x * 4); 212cc1dc7a3Sopenharmony_ci if (res == 0) 213cc1dc7a3Sopenharmony_ci { 214cc1dc7a3Sopenharmony_ci break; 215cc1dc7a3Sopenharmony_ci } 216cc1dc7a3Sopenharmony_ci } 217cc1dc7a3Sopenharmony_ci 218cc1dc7a3Sopenharmony_ci return res != 0; 219cc1dc7a3Sopenharmony_ci} 220cc1dc7a3Sopenharmony_ci 221cc1dc7a3Sopenharmony_ci/** 222cc1dc7a3Sopenharmony_ci * @brief Save a TGA image using STBImageWrite to provide the store routine. 223cc1dc7a3Sopenharmony_ci * 224cc1dc7a3Sopenharmony_ci * @param img The source data for the image. 225cc1dc7a3Sopenharmony_ci * @param filename The name of the file to save. 226cc1dc7a3Sopenharmony_ci * @param y_flip Should the image be vertically flipped? 227cc1dc7a3Sopenharmony_ci * 228cc1dc7a3Sopenharmony_ci * @return @c true if the image saved OK, @c false on error. 229cc1dc7a3Sopenharmony_ci */ 230cc1dc7a3Sopenharmony_cistatic bool store_tga_image_with_stb( 231cc1dc7a3Sopenharmony_ci const astcenc_image* img, 232cc1dc7a3Sopenharmony_ci const char* filename, 233cc1dc7a3Sopenharmony_ci int y_flip 234cc1dc7a3Sopenharmony_ci) { 235cc1dc7a3Sopenharmony_ci int res { 0 }; 236cc1dc7a3Sopenharmony_ci 237cc1dc7a3Sopenharmony_ci assert(img->data_type == ASTCENC_TYPE_U8); 238cc1dc7a3Sopenharmony_ci 239cc1dc7a3Sopenharmony_ci for (unsigned int i = 0; i < img->dim_z; i++) 240cc1dc7a3Sopenharmony_ci { 241cc1dc7a3Sopenharmony_ci std::string fnmod = get_output_filename(img, filename, i); 242cc1dc7a3Sopenharmony_ci uint8_t* buf = reinterpret_cast<uint8_t*>(img->data[i]); 243cc1dc7a3Sopenharmony_ci 244cc1dc7a3Sopenharmony_ci stbi_flip_vertically_on_write(y_flip); 245cc1dc7a3Sopenharmony_ci res = stbi_write_tga(fnmod.c_str(), img->dim_x, img->dim_y, 4, buf); 246cc1dc7a3Sopenharmony_ci if (res == 0) 247cc1dc7a3Sopenharmony_ci { 248cc1dc7a3Sopenharmony_ci break; 249cc1dc7a3Sopenharmony_ci } 250cc1dc7a3Sopenharmony_ci } 251cc1dc7a3Sopenharmony_ci 252cc1dc7a3Sopenharmony_ci return res != 0; 253cc1dc7a3Sopenharmony_ci} 254cc1dc7a3Sopenharmony_ci 255cc1dc7a3Sopenharmony_ci/** 256cc1dc7a3Sopenharmony_ci * @brief Save a BMP image using STBImageWrite to provide the store routine. 257cc1dc7a3Sopenharmony_ci * 258cc1dc7a3Sopenharmony_ci * @param img The source data for the image. 259cc1dc7a3Sopenharmony_ci * @param filename The name of the file to save. 260cc1dc7a3Sopenharmony_ci * @param y_flip Should the image be vertically flipped? 261cc1dc7a3Sopenharmony_ci * 262cc1dc7a3Sopenharmony_ci * @return @c true if the image saved OK, @c false on error. 263cc1dc7a3Sopenharmony_ci */ 264cc1dc7a3Sopenharmony_cistatic bool store_bmp_image_with_stb( 265cc1dc7a3Sopenharmony_ci const astcenc_image* img, 266cc1dc7a3Sopenharmony_ci const char* filename, 267cc1dc7a3Sopenharmony_ci int y_flip 268cc1dc7a3Sopenharmony_ci) { 269cc1dc7a3Sopenharmony_ci int res { 0 }; 270cc1dc7a3Sopenharmony_ci 271cc1dc7a3Sopenharmony_ci assert(img->data_type == ASTCENC_TYPE_U8); 272cc1dc7a3Sopenharmony_ci 273cc1dc7a3Sopenharmony_ci for (unsigned int i = 0; i < img->dim_z; i++) 274cc1dc7a3Sopenharmony_ci { 275cc1dc7a3Sopenharmony_ci std::string fnmod = get_output_filename(img, filename, i); 276cc1dc7a3Sopenharmony_ci uint8_t* buf = reinterpret_cast<uint8_t*>(img->data[i]); 277cc1dc7a3Sopenharmony_ci 278cc1dc7a3Sopenharmony_ci stbi_flip_vertically_on_write(y_flip); 279cc1dc7a3Sopenharmony_ci res = stbi_write_bmp(fnmod.c_str(), img->dim_x, img->dim_y, 4, buf); 280cc1dc7a3Sopenharmony_ci if (res == 0) 281cc1dc7a3Sopenharmony_ci { 282cc1dc7a3Sopenharmony_ci break; 283cc1dc7a3Sopenharmony_ci } 284cc1dc7a3Sopenharmony_ci } 285cc1dc7a3Sopenharmony_ci 286cc1dc7a3Sopenharmony_ci return res != 0; 287cc1dc7a3Sopenharmony_ci} 288cc1dc7a3Sopenharmony_ci 289cc1dc7a3Sopenharmony_ci/** 290cc1dc7a3Sopenharmony_ci * @brief Save a HDR image using STBImageWrite to provide the store routine. 291cc1dc7a3Sopenharmony_ci * 292cc1dc7a3Sopenharmony_ci * @param img The source data for the image. 293cc1dc7a3Sopenharmony_ci * @param filename The name of the file to save. 294cc1dc7a3Sopenharmony_ci * @param y_flip Should the image be vertically flipped? 295cc1dc7a3Sopenharmony_ci * 296cc1dc7a3Sopenharmony_ci * @return @c true if the image saved OK, @c false on error. 297cc1dc7a3Sopenharmony_ci */ 298cc1dc7a3Sopenharmony_cistatic bool store_hdr_image_with_stb( 299cc1dc7a3Sopenharmony_ci const astcenc_image* img, 300cc1dc7a3Sopenharmony_ci const char* filename, 301cc1dc7a3Sopenharmony_ci int y_flip 302cc1dc7a3Sopenharmony_ci) { 303cc1dc7a3Sopenharmony_ci int res { 0 }; 304cc1dc7a3Sopenharmony_ci 305cc1dc7a3Sopenharmony_ci for (unsigned int i = 0; i < img->dim_z; i++) 306cc1dc7a3Sopenharmony_ci { 307cc1dc7a3Sopenharmony_ci std::string fnmod = get_output_filename(img, filename, i); 308cc1dc7a3Sopenharmony_ci float* buf = floatx4_array_from_astc_img(img, y_flip, i); 309cc1dc7a3Sopenharmony_ci 310cc1dc7a3Sopenharmony_ci res = stbi_write_hdr(fnmod.c_str(), img->dim_x, img->dim_y, 4, buf); 311cc1dc7a3Sopenharmony_ci delete[] buf; 312cc1dc7a3Sopenharmony_ci if (res == 0) 313cc1dc7a3Sopenharmony_ci { 314cc1dc7a3Sopenharmony_ci break; 315cc1dc7a3Sopenharmony_ci } 316cc1dc7a3Sopenharmony_ci } 317cc1dc7a3Sopenharmony_ci 318cc1dc7a3Sopenharmony_ci return res != 0; 319cc1dc7a3Sopenharmony_ci} 320cc1dc7a3Sopenharmony_ci 321cc1dc7a3Sopenharmony_ci/* ============================================================================ 322cc1dc7a3Sopenharmony_ciNative Load and store of KTX and DDS file formats. 323cc1dc7a3Sopenharmony_ci 324cc1dc7a3Sopenharmony_ciUnlike "regular" 2D image formats, which are mostly supported through stb_image 325cc1dc7a3Sopenharmony_ciand tinyexr, these formats are supported directly; this involves a relatively 326cc1dc7a3Sopenharmony_cilarge number of pixel formats. 327cc1dc7a3Sopenharmony_ci 328cc1dc7a3Sopenharmony_ciThe following restrictions apply to loading of these file formats: 329cc1dc7a3Sopenharmony_ci 330cc1dc7a3Sopenharmony_ci * Only uncompressed data supported 331cc1dc7a3Sopenharmony_ci * Only first mipmap in mipmap pyramid supported 332cc1dc7a3Sopenharmony_ci * KTX: Cube-map arrays are not supported 333cc1dc7a3Sopenharmony_ci============================================================================ */ 334cc1dc7a3Sopenharmony_cienum scanline_transfer 335cc1dc7a3Sopenharmony_ci{ 336cc1dc7a3Sopenharmony_ci R8_TO_RGBA8, 337cc1dc7a3Sopenharmony_ci RG8_TO_RGBA8, 338cc1dc7a3Sopenharmony_ci RGB8_TO_RGBA8, 339cc1dc7a3Sopenharmony_ci RGBA8_TO_RGBA8, 340cc1dc7a3Sopenharmony_ci BGR8_TO_RGBA8, 341cc1dc7a3Sopenharmony_ci BGRA8_TO_RGBA8, 342cc1dc7a3Sopenharmony_ci L8_TO_RGBA8, 343cc1dc7a3Sopenharmony_ci LA8_TO_RGBA8, 344cc1dc7a3Sopenharmony_ci 345cc1dc7a3Sopenharmony_ci RGBX8_TO_RGBA8, 346cc1dc7a3Sopenharmony_ci BGRX8_TO_RGBA8, 347cc1dc7a3Sopenharmony_ci 348cc1dc7a3Sopenharmony_ci R16_TO_RGBA16F, 349cc1dc7a3Sopenharmony_ci RG16_TO_RGBA16F, 350cc1dc7a3Sopenharmony_ci RGB16_TO_RGBA16F, 351cc1dc7a3Sopenharmony_ci RGBA16_TO_RGBA16F, 352cc1dc7a3Sopenharmony_ci BGR16_TO_RGBA16F, 353cc1dc7a3Sopenharmony_ci BGRA16_TO_RGBA16F, 354cc1dc7a3Sopenharmony_ci L16_TO_RGBA16F, 355cc1dc7a3Sopenharmony_ci LA16_TO_RGBA16F, 356cc1dc7a3Sopenharmony_ci 357cc1dc7a3Sopenharmony_ci R16F_TO_RGBA16F, 358cc1dc7a3Sopenharmony_ci RG16F_TO_RGBA16F, 359cc1dc7a3Sopenharmony_ci RGB16F_TO_RGBA16F, 360cc1dc7a3Sopenharmony_ci RGBA16F_TO_RGBA16F, 361cc1dc7a3Sopenharmony_ci BGR16F_TO_RGBA16F, 362cc1dc7a3Sopenharmony_ci BGRA16F_TO_RGBA16F, 363cc1dc7a3Sopenharmony_ci L16F_TO_RGBA16F, 364cc1dc7a3Sopenharmony_ci LA16F_TO_RGBA16F, 365cc1dc7a3Sopenharmony_ci 366cc1dc7a3Sopenharmony_ci R32F_TO_RGBA16F, 367cc1dc7a3Sopenharmony_ci RG32F_TO_RGBA16F, 368cc1dc7a3Sopenharmony_ci RGB32F_TO_RGBA16F, 369cc1dc7a3Sopenharmony_ci RGBA32F_TO_RGBA16F, 370cc1dc7a3Sopenharmony_ci BGR32F_TO_RGBA16F, 371cc1dc7a3Sopenharmony_ci BGRA32F_TO_RGBA16F, 372cc1dc7a3Sopenharmony_ci L32F_TO_RGBA16F, 373cc1dc7a3Sopenharmony_ci LA32F_TO_RGBA16F 374cc1dc7a3Sopenharmony_ci}; 375cc1dc7a3Sopenharmony_ci 376cc1dc7a3Sopenharmony_ci/** 377cc1dc7a3Sopenharmony_ci * @brief Copy a scanline from a source file and expand to a canonical format. 378cc1dc7a3Sopenharmony_ci * 379cc1dc7a3Sopenharmony_ci * Outputs are always 4 component RGBA, stored as U8 (LDR) or FP16 (HDR). 380cc1dc7a3Sopenharmony_ci * 381cc1dc7a3Sopenharmony_ci * @param[out] dst The start of the line to store to. 382cc1dc7a3Sopenharmony_ci * @param src The start of the line to load. 383cc1dc7a3Sopenharmony_ci * @param pixel_count The number of pixels in the scanline. 384cc1dc7a3Sopenharmony_ci * @param method The conversion function. 385cc1dc7a3Sopenharmony_ci */ 386cc1dc7a3Sopenharmony_cistatic void copy_scanline( 387cc1dc7a3Sopenharmony_ci void* dst, 388cc1dc7a3Sopenharmony_ci const void* src, 389cc1dc7a3Sopenharmony_ci int pixel_count, 390cc1dc7a3Sopenharmony_ci scanline_transfer method 391cc1dc7a3Sopenharmony_ci) { 392cc1dc7a3Sopenharmony_ci 393cc1dc7a3Sopenharmony_ci#define id(x) (x) 394cc1dc7a3Sopenharmony_ci#define u16_sf16(x) float_to_float16(x * (1.0f/65535.0f)) 395cc1dc7a3Sopenharmony_ci#define f32_sf16(x) float_to_float16(x) 396cc1dc7a3Sopenharmony_ci 397cc1dc7a3Sopenharmony_ci#define COPY_R(dsttype, srctype, convfunc, oneval) \ 398cc1dc7a3Sopenharmony_ci do { \ 399cc1dc7a3Sopenharmony_ci const srctype* s = reinterpret_cast<const srctype*>(src); \ 400cc1dc7a3Sopenharmony_ci dsttype* d = reinterpret_cast<dsttype*>(dst); \ 401cc1dc7a3Sopenharmony_ci for (int i = 0; i < pixel_count; i++) \ 402cc1dc7a3Sopenharmony_ci { \ 403cc1dc7a3Sopenharmony_ci d[4 * i ] = convfunc(s[i]); \ 404cc1dc7a3Sopenharmony_ci d[4 * i + 1] = 0; \ 405cc1dc7a3Sopenharmony_ci d[4 * i + 2] = 0; \ 406cc1dc7a3Sopenharmony_ci d[4 * i + 3] = oneval; \ 407cc1dc7a3Sopenharmony_ci } \ 408cc1dc7a3Sopenharmony_ci } while (0); \ 409cc1dc7a3Sopenharmony_ci break 410cc1dc7a3Sopenharmony_ci 411cc1dc7a3Sopenharmony_ci#define COPY_RG(dsttype, srctype, convfunc, oneval) \ 412cc1dc7a3Sopenharmony_ci do { \ 413cc1dc7a3Sopenharmony_ci const srctype* s = reinterpret_cast<const srctype*>(src); \ 414cc1dc7a3Sopenharmony_ci dsttype* d = reinterpret_cast<dsttype*>(dst); \ 415cc1dc7a3Sopenharmony_ci for (int i = 0; i < pixel_count; i++) \ 416cc1dc7a3Sopenharmony_ci { \ 417cc1dc7a3Sopenharmony_ci d[4 * i ] = convfunc(s[2 * i ]); \ 418cc1dc7a3Sopenharmony_ci d[4 * i + 1] = convfunc(s[2 * i + 1]); \ 419cc1dc7a3Sopenharmony_ci d[4 * i + 2] = 0; \ 420cc1dc7a3Sopenharmony_ci d[4 * i + 3] = oneval; \ 421cc1dc7a3Sopenharmony_ci } \ 422cc1dc7a3Sopenharmony_ci } while (0); \ 423cc1dc7a3Sopenharmony_ci break 424cc1dc7a3Sopenharmony_ci 425cc1dc7a3Sopenharmony_ci#define COPY_RGB(dsttype, srctype, convfunc, oneval) \ 426cc1dc7a3Sopenharmony_ci do { \ 427cc1dc7a3Sopenharmony_ci const srctype* s = reinterpret_cast<const srctype*>(src); \ 428cc1dc7a3Sopenharmony_ci dsttype* d = reinterpret_cast<dsttype*>(dst); \ 429cc1dc7a3Sopenharmony_ci for (int i = 0; i < pixel_count; i++) \ 430cc1dc7a3Sopenharmony_ci { \ 431cc1dc7a3Sopenharmony_ci d[4 * i ] = convfunc(s[3 * i ]); \ 432cc1dc7a3Sopenharmony_ci d[4 * i + 1] = convfunc(s[3 * i + 1]); \ 433cc1dc7a3Sopenharmony_ci d[4 * i + 2] = convfunc(s[3 * i + 2]); \ 434cc1dc7a3Sopenharmony_ci d[4 * i + 3] = oneval; \ 435cc1dc7a3Sopenharmony_ci } \ 436cc1dc7a3Sopenharmony_ci } while (0); \ 437cc1dc7a3Sopenharmony_ci break 438cc1dc7a3Sopenharmony_ci 439cc1dc7a3Sopenharmony_ci#define COPY_BGR(dsttype, srctype, convfunc, oneval) \ 440cc1dc7a3Sopenharmony_ci do { \ 441cc1dc7a3Sopenharmony_ci const srctype* s = reinterpret_cast<const srctype*>(src); \ 442cc1dc7a3Sopenharmony_ci dsttype* d = reinterpret_cast<dsttype*>(dst); \ 443cc1dc7a3Sopenharmony_ci for (int i = 0; i < pixel_count; i++)\ 444cc1dc7a3Sopenharmony_ci { \ 445cc1dc7a3Sopenharmony_ci d[4 * i ] = convfunc(s[3 * i + 2]); \ 446cc1dc7a3Sopenharmony_ci d[4 * i + 1] = convfunc(s[3 * i + 1]); \ 447cc1dc7a3Sopenharmony_ci d[4 * i + 2] = convfunc(s[3 * i ]); \ 448cc1dc7a3Sopenharmony_ci d[4 * i + 3] = oneval; \ 449cc1dc7a3Sopenharmony_ci } \ 450cc1dc7a3Sopenharmony_ci } while (0); \ 451cc1dc7a3Sopenharmony_ci break 452cc1dc7a3Sopenharmony_ci 453cc1dc7a3Sopenharmony_ci#define COPY_RGBX(dsttype, srctype, convfunc, oneval) \ 454cc1dc7a3Sopenharmony_ci do { \ 455cc1dc7a3Sopenharmony_ci const srctype* s = reinterpret_cast<const srctype*>(src); \ 456cc1dc7a3Sopenharmony_ci dsttype* d = reinterpret_cast<dsttype*>(dst); \ 457cc1dc7a3Sopenharmony_ci for (int i = 0; i < pixel_count; i++)\ 458cc1dc7a3Sopenharmony_ci { \ 459cc1dc7a3Sopenharmony_ci d[4 * i ] = convfunc(s[4 * i ]); \ 460cc1dc7a3Sopenharmony_ci d[4 * i + 1] = convfunc(s[4 * i + 1]); \ 461cc1dc7a3Sopenharmony_ci d[4 * i + 2] = convfunc(s[4 * i + 2]); \ 462cc1dc7a3Sopenharmony_ci d[4 * i + 3] = oneval; \ 463cc1dc7a3Sopenharmony_ci } \ 464cc1dc7a3Sopenharmony_ci } while (0); \ 465cc1dc7a3Sopenharmony_ci break 466cc1dc7a3Sopenharmony_ci 467cc1dc7a3Sopenharmony_ci#define COPY_BGRX(dsttype, srctype, convfunc, oneval) \ 468cc1dc7a3Sopenharmony_ci do { \ 469cc1dc7a3Sopenharmony_ci const srctype* s = reinterpret_cast<const srctype*>(src); \ 470cc1dc7a3Sopenharmony_ci dsttype* d = reinterpret_cast<dsttype*>(dst); \ 471cc1dc7a3Sopenharmony_ci for (int i = 0; i < pixel_count; i++)\ 472cc1dc7a3Sopenharmony_ci { \ 473cc1dc7a3Sopenharmony_ci d[4 * i ] = convfunc(s[4 * i + 2]); \ 474cc1dc7a3Sopenharmony_ci d[4 * i + 1] = convfunc(s[4 * i + 1]); \ 475cc1dc7a3Sopenharmony_ci d[4 * i + 2] = convfunc(s[4 * i ]); \ 476cc1dc7a3Sopenharmony_ci d[4 * i + 3] = oneval; \ 477cc1dc7a3Sopenharmony_ci } \ 478cc1dc7a3Sopenharmony_ci } while (0); \ 479cc1dc7a3Sopenharmony_ci break 480cc1dc7a3Sopenharmony_ci 481cc1dc7a3Sopenharmony_ci#define COPY_RGBA(dsttype, srctype, convfunc, oneval) \ 482cc1dc7a3Sopenharmony_ci do { \ 483cc1dc7a3Sopenharmony_ci const srctype* s = reinterpret_cast<const srctype*>(src); \ 484cc1dc7a3Sopenharmony_ci dsttype* d = reinterpret_cast<dsttype*>(dst); \ 485cc1dc7a3Sopenharmony_ci for (int i = 0; i < pixel_count; i++) \ 486cc1dc7a3Sopenharmony_ci { \ 487cc1dc7a3Sopenharmony_ci d[4 * i ] = convfunc(s[4 * i ]); \ 488cc1dc7a3Sopenharmony_ci d[4 * i + 1] = convfunc(s[4 * i + 1]); \ 489cc1dc7a3Sopenharmony_ci d[4 * i + 2] = convfunc(s[4 * i + 2]); \ 490cc1dc7a3Sopenharmony_ci d[4 * i + 3] = convfunc(s[4 * i + 3]); \ 491cc1dc7a3Sopenharmony_ci } \ 492cc1dc7a3Sopenharmony_ci } while (0); \ 493cc1dc7a3Sopenharmony_ci break 494cc1dc7a3Sopenharmony_ci 495cc1dc7a3Sopenharmony_ci#define COPY_BGRA(dsttype, srctype, convfunc, oneval) \ 496cc1dc7a3Sopenharmony_ci do { \ 497cc1dc7a3Sopenharmony_ci const srctype* s = reinterpret_cast<const srctype*>(src); \ 498cc1dc7a3Sopenharmony_ci dsttype* d = reinterpret_cast<dsttype*>(dst); \ 499cc1dc7a3Sopenharmony_ci for (int i = 0; i < pixel_count; i++) \ 500cc1dc7a3Sopenharmony_ci { \ 501cc1dc7a3Sopenharmony_ci d[4 * i ] = convfunc(s[4 * i + 2]); \ 502cc1dc7a3Sopenharmony_ci d[4 * i + 1] = convfunc(s[4 * i + 1]); \ 503cc1dc7a3Sopenharmony_ci d[4 * i + 2] = convfunc(s[4 * i ]); \ 504cc1dc7a3Sopenharmony_ci d[4 * i + 3] = convfunc(s[4 * i + 3]); \ 505cc1dc7a3Sopenharmony_ci } \ 506cc1dc7a3Sopenharmony_ci } while (0); \ 507cc1dc7a3Sopenharmony_ci break 508cc1dc7a3Sopenharmony_ci 509cc1dc7a3Sopenharmony_ci#define COPY_L(dsttype, srctype, convfunc, oneval) \ 510cc1dc7a3Sopenharmony_ci do { \ 511cc1dc7a3Sopenharmony_ci const srctype* s = reinterpret_cast<const srctype*>(src); \ 512cc1dc7a3Sopenharmony_ci dsttype* d = reinterpret_cast<dsttype*>(dst); \ 513cc1dc7a3Sopenharmony_ci for (int i = 0; i < pixel_count; i++) \ 514cc1dc7a3Sopenharmony_ci { \ 515cc1dc7a3Sopenharmony_ci d[4 * i ] = convfunc(s[i]); \ 516cc1dc7a3Sopenharmony_ci d[4 * i + 1] = convfunc(s[i]); \ 517cc1dc7a3Sopenharmony_ci d[4 * i + 2] = convfunc(s[i]); \ 518cc1dc7a3Sopenharmony_ci d[4 * i + 3] = oneval; \ 519cc1dc7a3Sopenharmony_ci } \ 520cc1dc7a3Sopenharmony_ci } while (0); \ 521cc1dc7a3Sopenharmony_ci break 522cc1dc7a3Sopenharmony_ci 523cc1dc7a3Sopenharmony_ci#define COPY_LA(dsttype, srctype, convfunc, oneval) \ 524cc1dc7a3Sopenharmony_ci do { \ 525cc1dc7a3Sopenharmony_ci const srctype* s = reinterpret_cast<const srctype*>(src); \ 526cc1dc7a3Sopenharmony_ci dsttype* d = reinterpret_cast<dsttype*>(dst); \ 527cc1dc7a3Sopenharmony_ci for (int i = 0; i < pixel_count; i++) \ 528cc1dc7a3Sopenharmony_ci { \ 529cc1dc7a3Sopenharmony_ci d[4 * i ] = convfunc(s[2 * i ]); \ 530cc1dc7a3Sopenharmony_ci d[4 * i + 1] = convfunc(s[2 * i ]); \ 531cc1dc7a3Sopenharmony_ci d[4 * i + 2] = convfunc(s[2 * i ]); \ 532cc1dc7a3Sopenharmony_ci d[4 * i + 3] = convfunc(s[2 * i + 1]); \ 533cc1dc7a3Sopenharmony_ci } \ 534cc1dc7a3Sopenharmony_ci } while (0); \ 535cc1dc7a3Sopenharmony_ci break 536cc1dc7a3Sopenharmony_ci 537cc1dc7a3Sopenharmony_ci switch (method) 538cc1dc7a3Sopenharmony_ci { 539cc1dc7a3Sopenharmony_ci case R8_TO_RGBA8: 540cc1dc7a3Sopenharmony_ci COPY_R(uint8_t, uint8_t, id, 0xFF); 541cc1dc7a3Sopenharmony_ci case RG8_TO_RGBA8: 542cc1dc7a3Sopenharmony_ci COPY_RG(uint8_t, uint8_t, id, 0xFF); 543cc1dc7a3Sopenharmony_ci case RGB8_TO_RGBA8: 544cc1dc7a3Sopenharmony_ci COPY_RGB(uint8_t, uint8_t, id, 0xFF); 545cc1dc7a3Sopenharmony_ci case RGBA8_TO_RGBA8: 546cc1dc7a3Sopenharmony_ci COPY_RGBA(uint8_t, uint8_t, id, 0xFF); 547cc1dc7a3Sopenharmony_ci case BGR8_TO_RGBA8: 548cc1dc7a3Sopenharmony_ci COPY_BGR(uint8_t, uint8_t, id, 0xFF); 549cc1dc7a3Sopenharmony_ci case BGRA8_TO_RGBA8: 550cc1dc7a3Sopenharmony_ci COPY_BGRA(uint8_t, uint8_t, id, 0xFF); 551cc1dc7a3Sopenharmony_ci case RGBX8_TO_RGBA8: 552cc1dc7a3Sopenharmony_ci COPY_RGBX(uint8_t, uint8_t, id, 0xFF); 553cc1dc7a3Sopenharmony_ci case BGRX8_TO_RGBA8: 554cc1dc7a3Sopenharmony_ci COPY_BGRX(uint8_t, uint8_t, id, 0xFF); 555cc1dc7a3Sopenharmony_ci case L8_TO_RGBA8: 556cc1dc7a3Sopenharmony_ci COPY_L(uint8_t, uint8_t, id, 0xFF); 557cc1dc7a3Sopenharmony_ci case LA8_TO_RGBA8: 558cc1dc7a3Sopenharmony_ci COPY_LA(uint8_t, uint8_t, id, 0xFF); 559cc1dc7a3Sopenharmony_ci 560cc1dc7a3Sopenharmony_ci case R16F_TO_RGBA16F: 561cc1dc7a3Sopenharmony_ci COPY_R(uint16_t, uint16_t, id, 0x3C00); 562cc1dc7a3Sopenharmony_ci case RG16F_TO_RGBA16F: 563cc1dc7a3Sopenharmony_ci COPY_RG(uint16_t, uint16_t, id, 0x3C00); 564cc1dc7a3Sopenharmony_ci case RGB16F_TO_RGBA16F: 565cc1dc7a3Sopenharmony_ci COPY_RGB(uint16_t, uint16_t, id, 0x3C00); 566cc1dc7a3Sopenharmony_ci case RGBA16F_TO_RGBA16F: 567cc1dc7a3Sopenharmony_ci COPY_RGBA(uint16_t, uint16_t, id, 0x3C00); 568cc1dc7a3Sopenharmony_ci case BGR16F_TO_RGBA16F: 569cc1dc7a3Sopenharmony_ci COPY_BGR(uint16_t, uint16_t, id, 0x3C00); 570cc1dc7a3Sopenharmony_ci case BGRA16F_TO_RGBA16F: 571cc1dc7a3Sopenharmony_ci COPY_BGRA(uint16_t, uint16_t, id, 0x3C00); 572cc1dc7a3Sopenharmony_ci case L16F_TO_RGBA16F: 573cc1dc7a3Sopenharmony_ci COPY_L(uint16_t, uint16_t, id, 0x3C00); 574cc1dc7a3Sopenharmony_ci case LA16F_TO_RGBA16F: 575cc1dc7a3Sopenharmony_ci COPY_LA(uint16_t, uint16_t, id, 0x3C00); 576cc1dc7a3Sopenharmony_ci 577cc1dc7a3Sopenharmony_ci case R16_TO_RGBA16F: 578cc1dc7a3Sopenharmony_ci COPY_R(uint16_t, uint16_t, u16_sf16, 0x3C00); 579cc1dc7a3Sopenharmony_ci case RG16_TO_RGBA16F: 580cc1dc7a3Sopenharmony_ci COPY_RG(uint16_t, uint16_t, u16_sf16, 0x3C00); 581cc1dc7a3Sopenharmony_ci case RGB16_TO_RGBA16F: 582cc1dc7a3Sopenharmony_ci COPY_RGB(uint16_t, uint16_t, u16_sf16, 0x3C00); 583cc1dc7a3Sopenharmony_ci case RGBA16_TO_RGBA16F: 584cc1dc7a3Sopenharmony_ci COPY_RGBA(uint16_t, uint16_t, u16_sf16, 0x3C00); 585cc1dc7a3Sopenharmony_ci case BGR16_TO_RGBA16F: 586cc1dc7a3Sopenharmony_ci COPY_BGR(uint16_t, uint16_t, u16_sf16, 0x3C00); 587cc1dc7a3Sopenharmony_ci case BGRA16_TO_RGBA16F: 588cc1dc7a3Sopenharmony_ci COPY_BGRA(uint16_t, uint16_t, u16_sf16, 0x3C00); 589cc1dc7a3Sopenharmony_ci case L16_TO_RGBA16F: 590cc1dc7a3Sopenharmony_ci COPY_L(uint16_t, uint16_t, u16_sf16, 0x3C00); 591cc1dc7a3Sopenharmony_ci case LA16_TO_RGBA16F: 592cc1dc7a3Sopenharmony_ci COPY_LA(uint16_t, uint16_t, u16_sf16, 0x3C00); 593cc1dc7a3Sopenharmony_ci 594cc1dc7a3Sopenharmony_ci case R32F_TO_RGBA16F: 595cc1dc7a3Sopenharmony_ci COPY_R(uint16_t, float, f32_sf16, 0x3C00); 596cc1dc7a3Sopenharmony_ci case RG32F_TO_RGBA16F: 597cc1dc7a3Sopenharmony_ci COPY_RG(uint16_t, float, f32_sf16, 0x3C00); 598cc1dc7a3Sopenharmony_ci case RGB32F_TO_RGBA16F: 599cc1dc7a3Sopenharmony_ci COPY_RGB(uint16_t, float, f32_sf16, 0x3C00); 600cc1dc7a3Sopenharmony_ci case RGBA32F_TO_RGBA16F: 601cc1dc7a3Sopenharmony_ci COPY_RGBA(uint16_t, float, f32_sf16, 0x3C00); 602cc1dc7a3Sopenharmony_ci case BGR32F_TO_RGBA16F: 603cc1dc7a3Sopenharmony_ci COPY_BGR(uint16_t, float, f32_sf16, 0x3C00); 604cc1dc7a3Sopenharmony_ci case BGRA32F_TO_RGBA16F: 605cc1dc7a3Sopenharmony_ci COPY_BGRA(uint16_t, float, f32_sf16, 0x3C00); 606cc1dc7a3Sopenharmony_ci case L32F_TO_RGBA16F: 607cc1dc7a3Sopenharmony_ci COPY_L(uint16_t, float, f32_sf16, 0x3C00); 608cc1dc7a3Sopenharmony_ci case LA32F_TO_RGBA16F: 609cc1dc7a3Sopenharmony_ci COPY_LA(uint16_t, float, f32_sf16, 0x3C00); 610cc1dc7a3Sopenharmony_ci } 611cc1dc7a3Sopenharmony_ci} 612cc1dc7a3Sopenharmony_ci 613cc1dc7a3Sopenharmony_ci/** 614cc1dc7a3Sopenharmony_ci * @brief Swap endianness of N two byte values. 615cc1dc7a3Sopenharmony_ci * 616cc1dc7a3Sopenharmony_ci * @param[in,out] dataptr The data to convert. 617cc1dc7a3Sopenharmony_ci * @param byte_count The number of bytes to convert. 618cc1dc7a3Sopenharmony_ci */ 619cc1dc7a3Sopenharmony_cistatic void switch_endianness2( 620cc1dc7a3Sopenharmony_ci void* dataptr, 621cc1dc7a3Sopenharmony_ci int byte_count 622cc1dc7a3Sopenharmony_ci) { 623cc1dc7a3Sopenharmony_ci uint8_t* data = reinterpret_cast<uint8_t*>(dataptr); 624cc1dc7a3Sopenharmony_ci for (int i = 0; i < byte_count / 2; i++) 625cc1dc7a3Sopenharmony_ci { 626cc1dc7a3Sopenharmony_ci uint8_t d0 = data[0]; 627cc1dc7a3Sopenharmony_ci uint8_t d1 = data[1]; 628cc1dc7a3Sopenharmony_ci data[0] = d1; 629cc1dc7a3Sopenharmony_ci data[1] = d0; 630cc1dc7a3Sopenharmony_ci data += 2; 631cc1dc7a3Sopenharmony_ci } 632cc1dc7a3Sopenharmony_ci} 633cc1dc7a3Sopenharmony_ci 634cc1dc7a3Sopenharmony_ci/** 635cc1dc7a3Sopenharmony_ci * @brief Swap endianness of N four byte values. 636cc1dc7a3Sopenharmony_ci * 637cc1dc7a3Sopenharmony_ci * @param[in,out] dataptr The data to convert. 638cc1dc7a3Sopenharmony_ci * @param byte_count The number of bytes to convert. 639cc1dc7a3Sopenharmony_ci */ 640cc1dc7a3Sopenharmony_cistatic void switch_endianness4( 641cc1dc7a3Sopenharmony_ci void* dataptr, 642cc1dc7a3Sopenharmony_ci int byte_count 643cc1dc7a3Sopenharmony_ci) { 644cc1dc7a3Sopenharmony_ci uint8_t* data = reinterpret_cast<uint8_t*>(dataptr); 645cc1dc7a3Sopenharmony_ci for (int i = 0; i < byte_count / 4; i++) 646cc1dc7a3Sopenharmony_ci { 647cc1dc7a3Sopenharmony_ci uint8_t d0 = data[0]; 648cc1dc7a3Sopenharmony_ci uint8_t d1 = data[1]; 649cc1dc7a3Sopenharmony_ci uint8_t d2 = data[2]; 650cc1dc7a3Sopenharmony_ci uint8_t d3 = data[3]; 651cc1dc7a3Sopenharmony_ci data[0] = d3; 652cc1dc7a3Sopenharmony_ci data[1] = d2; 653cc1dc7a3Sopenharmony_ci data[2] = d1; 654cc1dc7a3Sopenharmony_ci data[3] = d0; 655cc1dc7a3Sopenharmony_ci data += 4; 656cc1dc7a3Sopenharmony_ci } 657cc1dc7a3Sopenharmony_ci} 658cc1dc7a3Sopenharmony_ci 659cc1dc7a3Sopenharmony_ci/** 660cc1dc7a3Sopenharmony_ci * @brief Swap endianness of a u32 value. 661cc1dc7a3Sopenharmony_ci * 662cc1dc7a3Sopenharmony_ci * @param v The data to convert. 663cc1dc7a3Sopenharmony_ci * 664cc1dc7a3Sopenharmony_ci * @return The converted value. 665cc1dc7a3Sopenharmony_ci */ 666cc1dc7a3Sopenharmony_cistatic uint32_t u32_byterev(uint32_t v) 667cc1dc7a3Sopenharmony_ci{ 668cc1dc7a3Sopenharmony_ci return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24); 669cc1dc7a3Sopenharmony_ci} 670cc1dc7a3Sopenharmony_ci 671cc1dc7a3Sopenharmony_ci/* 672cc1dc7a3Sopenharmony_ci Notes about KTX: 673cc1dc7a3Sopenharmony_ci 674cc1dc7a3Sopenharmony_ci After the header and the key/value data area, the actual image data follows. 675cc1dc7a3Sopenharmony_ci Each image starts with a 4-byte "imageSize" value indicating the number of bytes of image data follow. 676cc1dc7a3Sopenharmony_ci (For cube-maps, this value appears only after first image; the remaining 5 images are all of equal size.) 677cc1dc7a3Sopenharmony_ci If the size of an image is not a multiple of 4, then it is padded to the next multiple of 4. 678cc1dc7a3Sopenharmony_ci Note that this padding is NOT included in the "imageSize" field. 679cc1dc7a3Sopenharmony_ci In a cubemap, the padding appears after each face note that in a 2D/3D texture, padding does 680cc1dc7a3Sopenharmony_ci NOT appear between the lines/planes of the texture! 681cc1dc7a3Sopenharmony_ci 682cc1dc7a3Sopenharmony_ci In a KTX file, there may be multiple images; they are organized as follows: 683cc1dc7a3Sopenharmony_ci 684cc1dc7a3Sopenharmony_ci For each mipmap_level in numberOfMipmapLevels 685cc1dc7a3Sopenharmony_ci UInt32 imageSize; 686cc1dc7a3Sopenharmony_ci For each array_element in numberOfArrayElements 687cc1dc7a3Sopenharmony_ci * for each face in numberOfFaces 688cc1dc7a3Sopenharmony_ci * for each z_slice in pixelDepth 689cc1dc7a3Sopenharmony_ci * for each row or row_of_blocks in pixelHeight 690cc1dc7a3Sopenharmony_ci * for each pixel or block_of_pixels in pixelWidth 691cc1dc7a3Sopenharmony_ci Byte data[format-specific-number-of-bytes] 692cc1dc7a3Sopenharmony_ci * end 693cc1dc7a3Sopenharmony_ci * end 694cc1dc7a3Sopenharmony_ci *end 695cc1dc7a3Sopenharmony_ci Byte cubePadding[0-3] 696cc1dc7a3Sopenharmony_ci *end 697cc1dc7a3Sopenharmony_ci Byte mipPadding[3 - ((imageSize+ 3) % 4)] 698cc1dc7a3Sopenharmony_ci *end 699cc1dc7a3Sopenharmony_ci 700cc1dc7a3Sopenharmony_ci In the ASTC codec, we will, for the time being only harvest the first image, 701cc1dc7a3Sopenharmony_ci and we will support only a limited set of formats: 702cc1dc7a3Sopenharmony_ci 703cc1dc7a3Sopenharmony_ci gl_type: UNSIGNED_BYTE UNSIGNED_SHORT HALF_FLOAT FLOAT UNSIGNED_INT_8_8_8_8 UNSIGNED_INT_8_8_8_8_REV 704cc1dc7a3Sopenharmony_ci gl_format: RED, RG. RGB, RGBA BGR, BGRA 705cc1dc7a3Sopenharmony_ci gl_internal_format: used for upload to OpenGL; we can ignore it on uncompressed-load, but 706cc1dc7a3Sopenharmony_ci need to provide a reasonable value on store: RGB8 RGBA8 RGB16F RGBA16F 707cc1dc7a3Sopenharmony_ci gl_base_internal_format: same as gl_format unless texture is compressed (well, BGR is turned into RGB) 708cc1dc7a3Sopenharmony_ci RED, RG, RGB, RGBA 709cc1dc7a3Sopenharmony_ci*/ 710cc1dc7a3Sopenharmony_ci 711cc1dc7a3Sopenharmony_ci// Khronos enums 712cc1dc7a3Sopenharmony_ci#define GL_RED 0x1903 713cc1dc7a3Sopenharmony_ci#define GL_RG 0x8227 714cc1dc7a3Sopenharmony_ci#define GL_RGB 0x1907 715cc1dc7a3Sopenharmony_ci#define GL_RGBA 0x1908 716cc1dc7a3Sopenharmony_ci#define GL_BGR 0x80E0 717cc1dc7a3Sopenharmony_ci#define GL_BGRA 0x80E1 718cc1dc7a3Sopenharmony_ci#define GL_LUMINANCE 0x1909 719cc1dc7a3Sopenharmony_ci#define GL_LUMINANCE_ALPHA 0x190A 720cc1dc7a3Sopenharmony_ci 721cc1dc7a3Sopenharmony_ci#define GL_R8 0x8229 722cc1dc7a3Sopenharmony_ci#define GL_RG8 0x822B 723cc1dc7a3Sopenharmony_ci#define GL_RGB8 0x8051 724cc1dc7a3Sopenharmony_ci#define GL_RGBA8 0x8058 725cc1dc7a3Sopenharmony_ci 726cc1dc7a3Sopenharmony_ci#define GL_R16F 0x822D 727cc1dc7a3Sopenharmony_ci#define GL_RG16F 0x822F 728cc1dc7a3Sopenharmony_ci#define GL_RGB16F 0x881B 729cc1dc7a3Sopenharmony_ci#define GL_RGBA16F 0x881A 730cc1dc7a3Sopenharmony_ci 731cc1dc7a3Sopenharmony_ci#define GL_UNSIGNED_BYTE 0x1401 732cc1dc7a3Sopenharmony_ci#define GL_UNSIGNED_SHORT 0x1403 733cc1dc7a3Sopenharmony_ci#define GL_HALF_FLOAT 0x140B 734cc1dc7a3Sopenharmony_ci#define GL_FLOAT 0x1406 735cc1dc7a3Sopenharmony_ci 736cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_4x4 0x93B0 737cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_5x4 0x93B1 738cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_5x5 0x93B2 739cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_6x5 0x93B3 740cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_6x6 0x93B4 741cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_8x5 0x93B5 742cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_8x6 0x93B6 743cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_8x8 0x93B7 744cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_10x5 0x93B8 745cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_10x6 0x93B9 746cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_10x8 0x93BA 747cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_10x10 0x93BB 748cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_12x10 0x93BC 749cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_12x12 0x93BD 750cc1dc7a3Sopenharmony_ci 751cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 0x93D0 752cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 0x93D1 753cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 0x93D2 754cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 0x93D3 755cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 0x93D4 756cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 0x93D5 757cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 0x93D6 758cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 0x93D7 759cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 0x93D8 760cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 0x93D9 761cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 0x93DA 762cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 0x93DB 763cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 0x93DC 764cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 0x93DD 765cc1dc7a3Sopenharmony_ci 766cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_3x3x3_OES 0x93C0 767cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_4x3x3_OES 0x93C1 768cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_4x4x3_OES 0x93C2 769cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_4x4x4_OES 0x93C3 770cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_5x4x4_OES 0x93C4 771cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_5x5x4_OES 0x93C5 772cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_5x5x5_OES 0x93C6 773cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_6x5x5_OES 0x93C7 774cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_6x6x5_OES 0x93C8 775cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_RGBA_ASTC_6x6x6_OES 0x93C9 776cc1dc7a3Sopenharmony_ci 777cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES 0x93E0 778cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES 0x93E1 779cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES 0x93E2 780cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES 0x93E3 781cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES 0x93E4 782cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES 0x93E5 783cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES 0x93E6 784cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES 0x93E7 785cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES 0x93E8 786cc1dc7a3Sopenharmony_ci#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES 0x93E9 787cc1dc7a3Sopenharmony_ci 788cc1dc7a3Sopenharmony_cistruct format_entry 789cc1dc7a3Sopenharmony_ci{ 790cc1dc7a3Sopenharmony_ci unsigned int x; 791cc1dc7a3Sopenharmony_ci unsigned int y; 792cc1dc7a3Sopenharmony_ci unsigned int z; 793cc1dc7a3Sopenharmony_ci bool is_srgb; 794cc1dc7a3Sopenharmony_ci unsigned int format; 795cc1dc7a3Sopenharmony_ci}; 796cc1dc7a3Sopenharmony_ci 797cc1dc7a3Sopenharmony_cistatic const std::array<format_entry, 48> ASTC_FORMATS = 798cc1dc7a3Sopenharmony_ci{{ 799cc1dc7a3Sopenharmony_ci // 2D Linear RGB 800cc1dc7a3Sopenharmony_ci { 4, 4, 1, false, GL_COMPRESSED_RGBA_ASTC_4x4}, 801cc1dc7a3Sopenharmony_ci { 5, 4, 1, false, GL_COMPRESSED_RGBA_ASTC_5x4}, 802cc1dc7a3Sopenharmony_ci { 5, 5, 1, false, GL_COMPRESSED_RGBA_ASTC_5x5}, 803cc1dc7a3Sopenharmony_ci { 6, 5, 1, false, GL_COMPRESSED_RGBA_ASTC_6x5}, 804cc1dc7a3Sopenharmony_ci { 6, 6, 1, false, GL_COMPRESSED_RGBA_ASTC_6x6}, 805cc1dc7a3Sopenharmony_ci { 8, 5, 1, false, GL_COMPRESSED_RGBA_ASTC_8x5}, 806cc1dc7a3Sopenharmony_ci { 8, 6, 1, false, GL_COMPRESSED_RGBA_ASTC_8x6}, 807cc1dc7a3Sopenharmony_ci { 8, 8, 1, false, GL_COMPRESSED_RGBA_ASTC_8x8}, 808cc1dc7a3Sopenharmony_ci {10, 5, 1, false, GL_COMPRESSED_RGBA_ASTC_10x5}, 809cc1dc7a3Sopenharmony_ci {10, 6, 1, false, GL_COMPRESSED_RGBA_ASTC_10x6}, 810cc1dc7a3Sopenharmony_ci {10, 8, 1, false, GL_COMPRESSED_RGBA_ASTC_10x8}, 811cc1dc7a3Sopenharmony_ci {10, 10, 1, false, GL_COMPRESSED_RGBA_ASTC_10x10}, 812cc1dc7a3Sopenharmony_ci {12, 10, 1, false, GL_COMPRESSED_RGBA_ASTC_12x10}, 813cc1dc7a3Sopenharmony_ci {12, 12, 1, false, GL_COMPRESSED_RGBA_ASTC_12x12}, 814cc1dc7a3Sopenharmony_ci // 2D SRGB 815cc1dc7a3Sopenharmony_ci { 4, 4, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4}, 816cc1dc7a3Sopenharmony_ci { 5, 4, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4}, 817cc1dc7a3Sopenharmony_ci { 5, 5, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5}, 818cc1dc7a3Sopenharmony_ci { 6, 5, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5}, 819cc1dc7a3Sopenharmony_ci { 6, 6, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6}, 820cc1dc7a3Sopenharmony_ci { 8, 5, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5}, 821cc1dc7a3Sopenharmony_ci { 8, 6, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6}, 822cc1dc7a3Sopenharmony_ci { 8, 8, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8}, 823cc1dc7a3Sopenharmony_ci {10, 5, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5}, 824cc1dc7a3Sopenharmony_ci {10, 6, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6}, 825cc1dc7a3Sopenharmony_ci {10, 8, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8}, 826cc1dc7a3Sopenharmony_ci {10, 10, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10}, 827cc1dc7a3Sopenharmony_ci {12, 10, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10}, 828cc1dc7a3Sopenharmony_ci {12, 12, 1, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12}, 829cc1dc7a3Sopenharmony_ci // 3D Linear RGB 830cc1dc7a3Sopenharmony_ci { 3, 3, 3, false, GL_COMPRESSED_RGBA_ASTC_3x3x3_OES}, 831cc1dc7a3Sopenharmony_ci { 4, 3, 3, false, GL_COMPRESSED_RGBA_ASTC_4x3x3_OES}, 832cc1dc7a3Sopenharmony_ci { 4, 4, 3, false, GL_COMPRESSED_RGBA_ASTC_4x4x3_OES}, 833cc1dc7a3Sopenharmony_ci { 4, 4, 4, false, GL_COMPRESSED_RGBA_ASTC_4x4x4_OES}, 834cc1dc7a3Sopenharmony_ci { 5, 4, 4, false, GL_COMPRESSED_RGBA_ASTC_5x4x4_OES}, 835cc1dc7a3Sopenharmony_ci { 5, 5, 4, false, GL_COMPRESSED_RGBA_ASTC_5x5x4_OES}, 836cc1dc7a3Sopenharmony_ci { 5, 5, 5, false, GL_COMPRESSED_RGBA_ASTC_5x5x5_OES}, 837cc1dc7a3Sopenharmony_ci { 6, 5, 5, false, GL_COMPRESSED_RGBA_ASTC_6x5x5_OES}, 838cc1dc7a3Sopenharmony_ci { 6, 6, 5, false, GL_COMPRESSED_RGBA_ASTC_6x6x5_OES}, 839cc1dc7a3Sopenharmony_ci { 6, 6, 6, false, GL_COMPRESSED_RGBA_ASTC_6x6x6_OES}, 840cc1dc7a3Sopenharmony_ci // 3D SRGB 841cc1dc7a3Sopenharmony_ci { 3, 3, 3, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES}, 842cc1dc7a3Sopenharmony_ci { 4, 3, 3, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES}, 843cc1dc7a3Sopenharmony_ci { 4, 4, 3, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES}, 844cc1dc7a3Sopenharmony_ci { 4, 4, 4, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES}, 845cc1dc7a3Sopenharmony_ci { 5, 4, 4, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES}, 846cc1dc7a3Sopenharmony_ci { 5, 5, 4, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES}, 847cc1dc7a3Sopenharmony_ci { 5, 5, 5, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES}, 848cc1dc7a3Sopenharmony_ci { 6, 5, 5, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES}, 849cc1dc7a3Sopenharmony_ci { 6, 6, 5, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES}, 850cc1dc7a3Sopenharmony_ci { 6, 6, 6, true, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES} 851cc1dc7a3Sopenharmony_ci}}; 852cc1dc7a3Sopenharmony_ci 853cc1dc7a3Sopenharmony_cistatic const format_entry* get_format( 854cc1dc7a3Sopenharmony_ci unsigned int format 855cc1dc7a3Sopenharmony_ci) { 856cc1dc7a3Sopenharmony_ci for (auto& it : ASTC_FORMATS) 857cc1dc7a3Sopenharmony_ci { 858cc1dc7a3Sopenharmony_ci if (it.format == format) 859cc1dc7a3Sopenharmony_ci { 860cc1dc7a3Sopenharmony_ci return ⁢ 861cc1dc7a3Sopenharmony_ci } 862cc1dc7a3Sopenharmony_ci } 863cc1dc7a3Sopenharmony_ci return nullptr; 864cc1dc7a3Sopenharmony_ci} 865cc1dc7a3Sopenharmony_ci 866cc1dc7a3Sopenharmony_cistatic unsigned int get_format( 867cc1dc7a3Sopenharmony_ci unsigned int x, 868cc1dc7a3Sopenharmony_ci unsigned int y, 869cc1dc7a3Sopenharmony_ci unsigned int z, 870cc1dc7a3Sopenharmony_ci bool is_srgb 871cc1dc7a3Sopenharmony_ci) { 872cc1dc7a3Sopenharmony_ci for (auto& it : ASTC_FORMATS) 873cc1dc7a3Sopenharmony_ci { 874cc1dc7a3Sopenharmony_ci if ((it.x == x) && (it.y == y) && (it.z == z) && (it.is_srgb == is_srgb)) 875cc1dc7a3Sopenharmony_ci { 876cc1dc7a3Sopenharmony_ci return it.format; 877cc1dc7a3Sopenharmony_ci } 878cc1dc7a3Sopenharmony_ci } 879cc1dc7a3Sopenharmony_ci return 0; 880cc1dc7a3Sopenharmony_ci} 881cc1dc7a3Sopenharmony_ci 882cc1dc7a3Sopenharmony_cistruct ktx_header 883cc1dc7a3Sopenharmony_ci{ 884cc1dc7a3Sopenharmony_ci uint8_t magic[12]; 885cc1dc7a3Sopenharmony_ci uint32_t endianness; // should be 0x04030201; if it is instead 0x01020304, then the endianness of everything must be switched. 886cc1dc7a3Sopenharmony_ci uint32_t gl_type; // 0 for compressed textures, otherwise value from table 3.2 (page 162) of OpenGL 4.0 spec 887cc1dc7a3Sopenharmony_ci uint32_t gl_type_size; // size of data elements to do endianness swap on (1=endian-neutral data) 888cc1dc7a3Sopenharmony_ci uint32_t gl_format; // 0 for compressed textures, otherwise value from table 3.3 (page 163) of OpenGL spec 889cc1dc7a3Sopenharmony_ci uint32_t gl_internal_format; // sized-internal-format, corresponding to table 3.12 to 3.14 (pages 182-185) of OpenGL spec 890cc1dc7a3Sopenharmony_ci uint32_t gl_base_internal_format; // unsized-internal-format: corresponding to table 3.11 (page 179) of OpenGL spec 891cc1dc7a3Sopenharmony_ci uint32_t pixel_width; // texture dimensions; not rounded up to block size for compressed. 892cc1dc7a3Sopenharmony_ci uint32_t pixel_height; // must be 0 for 1D textures. 893cc1dc7a3Sopenharmony_ci uint32_t pixel_depth; // must be 0 for 1D, 2D and cubemap textures. 894cc1dc7a3Sopenharmony_ci uint32_t number_of_array_elements; // 0 if not a texture array 895cc1dc7a3Sopenharmony_ci uint32_t number_of_faces; // 6 for cubemaps, 1 for non-cubemaps 896cc1dc7a3Sopenharmony_ci uint32_t number_of_mipmap_levels; // 0 or 1 for non-mipmapped textures; 0 indicates that auto-mipmap-gen should be done at load time. 897cc1dc7a3Sopenharmony_ci uint32_t bytes_of_key_value_data; // size in bytes of the key-and-value area immediately following the header. 898cc1dc7a3Sopenharmony_ci}; 899cc1dc7a3Sopenharmony_ci 900cc1dc7a3Sopenharmony_ci// Magic 12-byte sequence that must appear at the beginning of every KTX file. 901cc1dc7a3Sopenharmony_cistatic uint8_t ktx_magic[12] { 902cc1dc7a3Sopenharmony_ci 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A 903cc1dc7a3Sopenharmony_ci}; 904cc1dc7a3Sopenharmony_ci 905cc1dc7a3Sopenharmony_cistatic void ktx_header_switch_endianness(ktx_header * kt) 906cc1dc7a3Sopenharmony_ci{ 907cc1dc7a3Sopenharmony_ci #define REV(x) kt->x = u32_byterev(kt->x) 908cc1dc7a3Sopenharmony_ci REV(endianness); 909cc1dc7a3Sopenharmony_ci REV(gl_type); 910cc1dc7a3Sopenharmony_ci REV(gl_type_size); 911cc1dc7a3Sopenharmony_ci REV(gl_format); 912cc1dc7a3Sopenharmony_ci REV(gl_internal_format); 913cc1dc7a3Sopenharmony_ci REV(gl_base_internal_format); 914cc1dc7a3Sopenharmony_ci REV(pixel_width); 915cc1dc7a3Sopenharmony_ci REV(pixel_height); 916cc1dc7a3Sopenharmony_ci REV(pixel_depth); 917cc1dc7a3Sopenharmony_ci REV(number_of_array_elements); 918cc1dc7a3Sopenharmony_ci REV(number_of_faces); 919cc1dc7a3Sopenharmony_ci REV(number_of_mipmap_levels); 920cc1dc7a3Sopenharmony_ci REV(bytes_of_key_value_data); 921cc1dc7a3Sopenharmony_ci #undef REV 922cc1dc7a3Sopenharmony_ci} 923cc1dc7a3Sopenharmony_ci 924cc1dc7a3Sopenharmony_ci/** 925cc1dc7a3Sopenharmony_ci * @brief Load an uncompressed KTX image using the local custom loader. 926cc1dc7a3Sopenharmony_ci * 927cc1dc7a3Sopenharmony_ci * @param filename The name of the file to load. 928cc1dc7a3Sopenharmony_ci * @param y_flip Should the image be vertically flipped? 929cc1dc7a3Sopenharmony_ci * @param[out] is_hdr Is this an HDR image load? 930cc1dc7a3Sopenharmony_ci * @param[out] component_count The number of components in the data. 931cc1dc7a3Sopenharmony_ci * 932cc1dc7a3Sopenharmony_ci * @return The loaded image data in a canonical 4 channel format, or @c nullptr on error. 933cc1dc7a3Sopenharmony_ci */ 934cc1dc7a3Sopenharmony_cistatic astcenc_image* load_ktx_uncompressed_image( 935cc1dc7a3Sopenharmony_ci const char* filename, 936cc1dc7a3Sopenharmony_ci bool y_flip, 937cc1dc7a3Sopenharmony_ci bool& is_hdr, 938cc1dc7a3Sopenharmony_ci unsigned int& component_count 939cc1dc7a3Sopenharmony_ci) { 940cc1dc7a3Sopenharmony_ci FILE *f = fopen(filename, "rb"); 941cc1dc7a3Sopenharmony_ci if (!f) 942cc1dc7a3Sopenharmony_ci { 943cc1dc7a3Sopenharmony_ci printf("Failed to open file %s\n", filename); 944cc1dc7a3Sopenharmony_ci return nullptr; 945cc1dc7a3Sopenharmony_ci } 946cc1dc7a3Sopenharmony_ci 947cc1dc7a3Sopenharmony_ci ktx_header hdr; 948cc1dc7a3Sopenharmony_ci size_t header_bytes_read = fread(&hdr, 1, sizeof(hdr), f); 949cc1dc7a3Sopenharmony_ci 950cc1dc7a3Sopenharmony_ci if (header_bytes_read != sizeof(hdr)) 951cc1dc7a3Sopenharmony_ci { 952cc1dc7a3Sopenharmony_ci printf("Failed to read header of KTX file %s\n", filename); 953cc1dc7a3Sopenharmony_ci fclose(f); 954cc1dc7a3Sopenharmony_ci return nullptr; 955cc1dc7a3Sopenharmony_ci } 956cc1dc7a3Sopenharmony_ci 957cc1dc7a3Sopenharmony_ci if (memcmp(hdr.magic, ktx_magic, 12) != 0 || (hdr.endianness != 0x04030201 && hdr.endianness != 0x01020304)) 958cc1dc7a3Sopenharmony_ci { 959cc1dc7a3Sopenharmony_ci printf("File %s does not have a valid KTX header\n", filename); 960cc1dc7a3Sopenharmony_ci fclose(f); 961cc1dc7a3Sopenharmony_ci return nullptr; 962cc1dc7a3Sopenharmony_ci } 963cc1dc7a3Sopenharmony_ci 964cc1dc7a3Sopenharmony_ci int switch_endianness = 0; 965cc1dc7a3Sopenharmony_ci if (hdr.endianness == 0x01020304) 966cc1dc7a3Sopenharmony_ci { 967cc1dc7a3Sopenharmony_ci ktx_header_switch_endianness(&hdr); 968cc1dc7a3Sopenharmony_ci switch_endianness = 1; 969cc1dc7a3Sopenharmony_ci } 970cc1dc7a3Sopenharmony_ci 971cc1dc7a3Sopenharmony_ci if (hdr.gl_type == 0 || hdr.gl_format == 0) 972cc1dc7a3Sopenharmony_ci { 973cc1dc7a3Sopenharmony_ci printf("File %s appears to be compressed, not supported as input\n", filename); 974cc1dc7a3Sopenharmony_ci fclose(f); 975cc1dc7a3Sopenharmony_ci return nullptr; 976cc1dc7a3Sopenharmony_ci } 977cc1dc7a3Sopenharmony_ci 978cc1dc7a3Sopenharmony_ci // the formats we support are: 979cc1dc7a3Sopenharmony_ci 980cc1dc7a3Sopenharmony_ci // Cartesian product of gl_type=(UNSIGNED_BYTE, UNSIGNED_SHORT, HALF_FLOAT, FLOAT) x gl_format=(RED, RG, RGB, RGBA, BGR, BGRA) 981cc1dc7a3Sopenharmony_ci 982cc1dc7a3Sopenharmony_ci int components; 983cc1dc7a3Sopenharmony_ci switch (hdr.gl_format) 984cc1dc7a3Sopenharmony_ci { 985cc1dc7a3Sopenharmony_ci case GL_RED: 986cc1dc7a3Sopenharmony_ci components = 1; 987cc1dc7a3Sopenharmony_ci break; 988cc1dc7a3Sopenharmony_ci case GL_RG: 989cc1dc7a3Sopenharmony_ci components = 2; 990cc1dc7a3Sopenharmony_ci break; 991cc1dc7a3Sopenharmony_ci case GL_RGB: 992cc1dc7a3Sopenharmony_ci components = 3; 993cc1dc7a3Sopenharmony_ci break; 994cc1dc7a3Sopenharmony_ci case GL_RGBA: 995cc1dc7a3Sopenharmony_ci components = 4; 996cc1dc7a3Sopenharmony_ci break; 997cc1dc7a3Sopenharmony_ci case GL_BGR: 998cc1dc7a3Sopenharmony_ci components = 3; 999cc1dc7a3Sopenharmony_ci break; 1000cc1dc7a3Sopenharmony_ci case GL_BGRA: 1001cc1dc7a3Sopenharmony_ci components = 4; 1002cc1dc7a3Sopenharmony_ci break; 1003cc1dc7a3Sopenharmony_ci case GL_LUMINANCE: 1004cc1dc7a3Sopenharmony_ci components = 1; 1005cc1dc7a3Sopenharmony_ci break; 1006cc1dc7a3Sopenharmony_ci case GL_LUMINANCE_ALPHA: 1007cc1dc7a3Sopenharmony_ci components = 2; 1008cc1dc7a3Sopenharmony_ci break; 1009cc1dc7a3Sopenharmony_ci default: 1010cc1dc7a3Sopenharmony_ci printf("KTX file %s has unsupported GL type\n", filename); 1011cc1dc7a3Sopenharmony_ci fclose(f); 1012cc1dc7a3Sopenharmony_ci return nullptr; 1013cc1dc7a3Sopenharmony_ci } 1014cc1dc7a3Sopenharmony_ci 1015cc1dc7a3Sopenharmony_ci // Although these are set up later, use default initializer to remove warnings 1016cc1dc7a3Sopenharmony_ci int bitness = 8; // Internal precision after conversion 1017cc1dc7a3Sopenharmony_ci int bytes_per_component = 1; // Bytes per component in the KTX file 1018cc1dc7a3Sopenharmony_ci scanline_transfer copy_method = R8_TO_RGBA8; 1019cc1dc7a3Sopenharmony_ci 1020cc1dc7a3Sopenharmony_ci switch (hdr.gl_type) 1021cc1dc7a3Sopenharmony_ci { 1022cc1dc7a3Sopenharmony_ci case GL_UNSIGNED_BYTE: 1023cc1dc7a3Sopenharmony_ci { 1024cc1dc7a3Sopenharmony_ci bitness = 8; 1025cc1dc7a3Sopenharmony_ci bytes_per_component = 1; 1026cc1dc7a3Sopenharmony_ci switch (hdr.gl_format) 1027cc1dc7a3Sopenharmony_ci { 1028cc1dc7a3Sopenharmony_ci case GL_RED: 1029cc1dc7a3Sopenharmony_ci copy_method = R8_TO_RGBA8; 1030cc1dc7a3Sopenharmony_ci break; 1031cc1dc7a3Sopenharmony_ci case GL_RG: 1032cc1dc7a3Sopenharmony_ci copy_method = RG8_TO_RGBA8; 1033cc1dc7a3Sopenharmony_ci break; 1034cc1dc7a3Sopenharmony_ci case GL_RGB: 1035cc1dc7a3Sopenharmony_ci copy_method = RGB8_TO_RGBA8; 1036cc1dc7a3Sopenharmony_ci break; 1037cc1dc7a3Sopenharmony_ci case GL_RGBA: 1038cc1dc7a3Sopenharmony_ci copy_method = RGBA8_TO_RGBA8; 1039cc1dc7a3Sopenharmony_ci break; 1040cc1dc7a3Sopenharmony_ci case GL_BGR: 1041cc1dc7a3Sopenharmony_ci copy_method = BGR8_TO_RGBA8; 1042cc1dc7a3Sopenharmony_ci break; 1043cc1dc7a3Sopenharmony_ci case GL_BGRA: 1044cc1dc7a3Sopenharmony_ci copy_method = BGRA8_TO_RGBA8; 1045cc1dc7a3Sopenharmony_ci break; 1046cc1dc7a3Sopenharmony_ci case GL_LUMINANCE: 1047cc1dc7a3Sopenharmony_ci copy_method = L8_TO_RGBA8; 1048cc1dc7a3Sopenharmony_ci break; 1049cc1dc7a3Sopenharmony_ci case GL_LUMINANCE_ALPHA: 1050cc1dc7a3Sopenharmony_ci copy_method = LA8_TO_RGBA8; 1051cc1dc7a3Sopenharmony_ci break; 1052cc1dc7a3Sopenharmony_ci } 1053cc1dc7a3Sopenharmony_ci break; 1054cc1dc7a3Sopenharmony_ci } 1055cc1dc7a3Sopenharmony_ci case GL_UNSIGNED_SHORT: 1056cc1dc7a3Sopenharmony_ci { 1057cc1dc7a3Sopenharmony_ci bitness = 16; 1058cc1dc7a3Sopenharmony_ci bytes_per_component = 2; 1059cc1dc7a3Sopenharmony_ci switch (hdr.gl_format) 1060cc1dc7a3Sopenharmony_ci { 1061cc1dc7a3Sopenharmony_ci case GL_RED: 1062cc1dc7a3Sopenharmony_ci copy_method = R16_TO_RGBA16F; 1063cc1dc7a3Sopenharmony_ci break; 1064cc1dc7a3Sopenharmony_ci case GL_RG: 1065cc1dc7a3Sopenharmony_ci copy_method = RG16_TO_RGBA16F; 1066cc1dc7a3Sopenharmony_ci break; 1067cc1dc7a3Sopenharmony_ci case GL_RGB: 1068cc1dc7a3Sopenharmony_ci copy_method = RGB16_TO_RGBA16F; 1069cc1dc7a3Sopenharmony_ci break; 1070cc1dc7a3Sopenharmony_ci case GL_RGBA: 1071cc1dc7a3Sopenharmony_ci copy_method = RGBA16_TO_RGBA16F; 1072cc1dc7a3Sopenharmony_ci break; 1073cc1dc7a3Sopenharmony_ci case GL_BGR: 1074cc1dc7a3Sopenharmony_ci copy_method = BGR16_TO_RGBA16F; 1075cc1dc7a3Sopenharmony_ci break; 1076cc1dc7a3Sopenharmony_ci case GL_BGRA: 1077cc1dc7a3Sopenharmony_ci copy_method = BGRA16_TO_RGBA16F; 1078cc1dc7a3Sopenharmony_ci break; 1079cc1dc7a3Sopenharmony_ci case GL_LUMINANCE: 1080cc1dc7a3Sopenharmony_ci copy_method = L16_TO_RGBA16F; 1081cc1dc7a3Sopenharmony_ci break; 1082cc1dc7a3Sopenharmony_ci case GL_LUMINANCE_ALPHA: 1083cc1dc7a3Sopenharmony_ci copy_method = LA16_TO_RGBA16F; 1084cc1dc7a3Sopenharmony_ci break; 1085cc1dc7a3Sopenharmony_ci } 1086cc1dc7a3Sopenharmony_ci break; 1087cc1dc7a3Sopenharmony_ci } 1088cc1dc7a3Sopenharmony_ci case GL_HALF_FLOAT: 1089cc1dc7a3Sopenharmony_ci { 1090cc1dc7a3Sopenharmony_ci bitness = 16; 1091cc1dc7a3Sopenharmony_ci bytes_per_component = 2; 1092cc1dc7a3Sopenharmony_ci switch (hdr.gl_format) 1093cc1dc7a3Sopenharmony_ci { 1094cc1dc7a3Sopenharmony_ci case GL_RED: 1095cc1dc7a3Sopenharmony_ci copy_method = R16F_TO_RGBA16F; 1096cc1dc7a3Sopenharmony_ci break; 1097cc1dc7a3Sopenharmony_ci case GL_RG: 1098cc1dc7a3Sopenharmony_ci copy_method = RG16F_TO_RGBA16F; 1099cc1dc7a3Sopenharmony_ci break; 1100cc1dc7a3Sopenharmony_ci case GL_RGB: 1101cc1dc7a3Sopenharmony_ci copy_method = RGB16F_TO_RGBA16F; 1102cc1dc7a3Sopenharmony_ci break; 1103cc1dc7a3Sopenharmony_ci case GL_RGBA: 1104cc1dc7a3Sopenharmony_ci copy_method = RGBA16F_TO_RGBA16F; 1105cc1dc7a3Sopenharmony_ci break; 1106cc1dc7a3Sopenharmony_ci case GL_BGR: 1107cc1dc7a3Sopenharmony_ci copy_method = BGR16F_TO_RGBA16F; 1108cc1dc7a3Sopenharmony_ci break; 1109cc1dc7a3Sopenharmony_ci case GL_BGRA: 1110cc1dc7a3Sopenharmony_ci copy_method = BGRA16F_TO_RGBA16F; 1111cc1dc7a3Sopenharmony_ci break; 1112cc1dc7a3Sopenharmony_ci case GL_LUMINANCE: 1113cc1dc7a3Sopenharmony_ci copy_method = L16F_TO_RGBA16F; 1114cc1dc7a3Sopenharmony_ci break; 1115cc1dc7a3Sopenharmony_ci case GL_LUMINANCE_ALPHA: 1116cc1dc7a3Sopenharmony_ci copy_method = LA16F_TO_RGBA16F; 1117cc1dc7a3Sopenharmony_ci break; 1118cc1dc7a3Sopenharmony_ci } 1119cc1dc7a3Sopenharmony_ci break; 1120cc1dc7a3Sopenharmony_ci } 1121cc1dc7a3Sopenharmony_ci case GL_FLOAT: 1122cc1dc7a3Sopenharmony_ci { 1123cc1dc7a3Sopenharmony_ci bitness = 16; 1124cc1dc7a3Sopenharmony_ci bytes_per_component = 4; 1125cc1dc7a3Sopenharmony_ci switch (hdr.gl_format) 1126cc1dc7a3Sopenharmony_ci { 1127cc1dc7a3Sopenharmony_ci case GL_RED: 1128cc1dc7a3Sopenharmony_ci copy_method = R32F_TO_RGBA16F; 1129cc1dc7a3Sopenharmony_ci break; 1130cc1dc7a3Sopenharmony_ci case GL_RG: 1131cc1dc7a3Sopenharmony_ci copy_method = RG32F_TO_RGBA16F; 1132cc1dc7a3Sopenharmony_ci break; 1133cc1dc7a3Sopenharmony_ci case GL_RGB: 1134cc1dc7a3Sopenharmony_ci copy_method = RGB32F_TO_RGBA16F; 1135cc1dc7a3Sopenharmony_ci break; 1136cc1dc7a3Sopenharmony_ci case GL_RGBA: 1137cc1dc7a3Sopenharmony_ci copy_method = RGBA32F_TO_RGBA16F; 1138cc1dc7a3Sopenharmony_ci break; 1139cc1dc7a3Sopenharmony_ci case GL_BGR: 1140cc1dc7a3Sopenharmony_ci copy_method = BGR32F_TO_RGBA16F; 1141cc1dc7a3Sopenharmony_ci break; 1142cc1dc7a3Sopenharmony_ci case GL_BGRA: 1143cc1dc7a3Sopenharmony_ci copy_method = BGRA32F_TO_RGBA16F; 1144cc1dc7a3Sopenharmony_ci break; 1145cc1dc7a3Sopenharmony_ci case GL_LUMINANCE: 1146cc1dc7a3Sopenharmony_ci copy_method = L32F_TO_RGBA16F; 1147cc1dc7a3Sopenharmony_ci break; 1148cc1dc7a3Sopenharmony_ci case GL_LUMINANCE_ALPHA: 1149cc1dc7a3Sopenharmony_ci copy_method = LA32F_TO_RGBA16F; 1150cc1dc7a3Sopenharmony_ci break; 1151cc1dc7a3Sopenharmony_ci } 1152cc1dc7a3Sopenharmony_ci break; 1153cc1dc7a3Sopenharmony_ci } 1154cc1dc7a3Sopenharmony_ci default: 1155cc1dc7a3Sopenharmony_ci printf("KTX file %s has unsupported GL format\n", filename); 1156cc1dc7a3Sopenharmony_ci fclose(f); 1157cc1dc7a3Sopenharmony_ci return nullptr; 1158cc1dc7a3Sopenharmony_ci } 1159cc1dc7a3Sopenharmony_ci 1160cc1dc7a3Sopenharmony_ci if (hdr.number_of_mipmap_levels > 1) 1161cc1dc7a3Sopenharmony_ci { 1162cc1dc7a3Sopenharmony_ci printf("WARNING: KTX file %s has %d mipmap levels; only the first one will be encoded.\n", filename, hdr.number_of_mipmap_levels); 1163cc1dc7a3Sopenharmony_ci } 1164cc1dc7a3Sopenharmony_ci 1165cc1dc7a3Sopenharmony_ci if (hdr.number_of_array_elements > 1) 1166cc1dc7a3Sopenharmony_ci { 1167cc1dc7a3Sopenharmony_ci printf("WARNING: KTX file %s contains a texture array with %d layers; only the first one will be encoded.\n", filename, hdr.number_of_array_elements); 1168cc1dc7a3Sopenharmony_ci } 1169cc1dc7a3Sopenharmony_ci 1170cc1dc7a3Sopenharmony_ci if (hdr.number_of_faces > 1) 1171cc1dc7a3Sopenharmony_ci { 1172cc1dc7a3Sopenharmony_ci printf("WARNING: KTX file %s contains a cubemap with 6 faces; only the first one will be encoded.\n", filename); 1173cc1dc7a3Sopenharmony_ci } 1174cc1dc7a3Sopenharmony_ci 1175cc1dc7a3Sopenharmony_ci 1176cc1dc7a3Sopenharmony_ci unsigned int dim_x = hdr.pixel_width; 1177cc1dc7a3Sopenharmony_ci unsigned int dim_y = astc::max(hdr.pixel_height, 1u); 1178cc1dc7a3Sopenharmony_ci unsigned int dim_z = astc::max(hdr.pixel_depth, 1u); 1179cc1dc7a3Sopenharmony_ci 1180cc1dc7a3Sopenharmony_ci // ignore the key/value data 1181cc1dc7a3Sopenharmony_ci fseek(f, hdr.bytes_of_key_value_data, SEEK_CUR); 1182cc1dc7a3Sopenharmony_ci 1183cc1dc7a3Sopenharmony_ci uint32_t specified_bytes_of_surface = 0; 1184cc1dc7a3Sopenharmony_ci size_t sb_read = fread(&specified_bytes_of_surface, 1, 4, f); 1185cc1dc7a3Sopenharmony_ci if (sb_read != 4) 1186cc1dc7a3Sopenharmony_ci { 1187cc1dc7a3Sopenharmony_ci printf("Failed to read header of KTX file %s\n", filename); 1188cc1dc7a3Sopenharmony_ci fclose(f); 1189cc1dc7a3Sopenharmony_ci return nullptr; 1190cc1dc7a3Sopenharmony_ci } 1191cc1dc7a3Sopenharmony_ci 1192cc1dc7a3Sopenharmony_ci if (switch_endianness) 1193cc1dc7a3Sopenharmony_ci { 1194cc1dc7a3Sopenharmony_ci specified_bytes_of_surface = u32_byterev(specified_bytes_of_surface); 1195cc1dc7a3Sopenharmony_ci } 1196cc1dc7a3Sopenharmony_ci 1197cc1dc7a3Sopenharmony_ci // read the surface 1198cc1dc7a3Sopenharmony_ci uint32_t xstride = bytes_per_component * components * dim_x; 1199cc1dc7a3Sopenharmony_ci uint32_t ystride = xstride * dim_y; 1200cc1dc7a3Sopenharmony_ci uint32_t computed_bytes_of_surface = dim_z * ystride; 1201cc1dc7a3Sopenharmony_ci if (computed_bytes_of_surface != specified_bytes_of_surface) 1202cc1dc7a3Sopenharmony_ci { 1203cc1dc7a3Sopenharmony_ci fclose(f); 1204cc1dc7a3Sopenharmony_ci printf("%s: KTX file inconsistency: computed surface size is %d bytes, but specified size is %d bytes\n", filename, computed_bytes_of_surface, specified_bytes_of_surface); 1205cc1dc7a3Sopenharmony_ci return nullptr; 1206cc1dc7a3Sopenharmony_ci } 1207cc1dc7a3Sopenharmony_ci 1208cc1dc7a3Sopenharmony_ci uint8_t *buf = new uint8_t[specified_bytes_of_surface]; 1209cc1dc7a3Sopenharmony_ci size_t bytes_read = fread(buf, 1, specified_bytes_of_surface, f); 1210cc1dc7a3Sopenharmony_ci fclose(f); 1211cc1dc7a3Sopenharmony_ci if (bytes_read != specified_bytes_of_surface) 1212cc1dc7a3Sopenharmony_ci { 1213cc1dc7a3Sopenharmony_ci delete[] buf; 1214cc1dc7a3Sopenharmony_ci printf("Failed to read file %s\n", filename); 1215cc1dc7a3Sopenharmony_ci return nullptr; 1216cc1dc7a3Sopenharmony_ci } 1217cc1dc7a3Sopenharmony_ci 1218cc1dc7a3Sopenharmony_ci // perform an endianness swap on the surface if needed. 1219cc1dc7a3Sopenharmony_ci if (switch_endianness) 1220cc1dc7a3Sopenharmony_ci { 1221cc1dc7a3Sopenharmony_ci if (hdr.gl_type_size == 2) 1222cc1dc7a3Sopenharmony_ci { 1223cc1dc7a3Sopenharmony_ci switch_endianness2(buf, specified_bytes_of_surface); 1224cc1dc7a3Sopenharmony_ci } 1225cc1dc7a3Sopenharmony_ci 1226cc1dc7a3Sopenharmony_ci if (hdr.gl_type_size == 4) 1227cc1dc7a3Sopenharmony_ci { 1228cc1dc7a3Sopenharmony_ci switch_endianness4(buf, specified_bytes_of_surface); 1229cc1dc7a3Sopenharmony_ci } 1230cc1dc7a3Sopenharmony_ci } 1231cc1dc7a3Sopenharmony_ci 1232cc1dc7a3Sopenharmony_ci // Transfer data from the surface to our own image data structure 1233cc1dc7a3Sopenharmony_ci astcenc_image *astc_img = alloc_image(bitness, dim_x, dim_y, dim_z); 1234cc1dc7a3Sopenharmony_ci 1235cc1dc7a3Sopenharmony_ci for (unsigned int z = 0; z < dim_z; z++) 1236cc1dc7a3Sopenharmony_ci { 1237cc1dc7a3Sopenharmony_ci for (unsigned int y = 0; y < dim_y; y++) 1238cc1dc7a3Sopenharmony_ci { 1239cc1dc7a3Sopenharmony_ci unsigned int ymod = y_flip ? dim_y - y - 1 : y; 1240cc1dc7a3Sopenharmony_ci unsigned int ydst = ymod; 1241cc1dc7a3Sopenharmony_ci void *dst; 1242cc1dc7a3Sopenharmony_ci 1243cc1dc7a3Sopenharmony_ci if (astc_img->data_type == ASTCENC_TYPE_U8) 1244cc1dc7a3Sopenharmony_ci { 1245cc1dc7a3Sopenharmony_ci uint8_t* data8 = static_cast<uint8_t*>(astc_img->data[z]); 1246cc1dc7a3Sopenharmony_ci dst = static_cast<void*>(&data8[4 * dim_x * ydst]); 1247cc1dc7a3Sopenharmony_ci } 1248cc1dc7a3Sopenharmony_ci else // if (astc_img->data_type == ASTCENC_TYPE_F16) 1249cc1dc7a3Sopenharmony_ci { 1250cc1dc7a3Sopenharmony_ci assert(astc_img->data_type == ASTCENC_TYPE_F16); 1251cc1dc7a3Sopenharmony_ci uint16_t* data16 = static_cast<uint16_t*>(astc_img->data[z]); 1252cc1dc7a3Sopenharmony_ci dst = static_cast<void*>(&data16[4 * dim_x * ydst]); 1253cc1dc7a3Sopenharmony_ci } 1254cc1dc7a3Sopenharmony_ci 1255cc1dc7a3Sopenharmony_ci uint8_t *src = buf + (z * ystride) + (y * xstride); 1256cc1dc7a3Sopenharmony_ci copy_scanline(dst, src, dim_x, copy_method); 1257cc1dc7a3Sopenharmony_ci } 1258cc1dc7a3Sopenharmony_ci } 1259cc1dc7a3Sopenharmony_ci 1260cc1dc7a3Sopenharmony_ci delete[] buf; 1261cc1dc7a3Sopenharmony_ci is_hdr = bitness >= 16; 1262cc1dc7a3Sopenharmony_ci component_count = components; 1263cc1dc7a3Sopenharmony_ci return astc_img; 1264cc1dc7a3Sopenharmony_ci} 1265cc1dc7a3Sopenharmony_ci 1266cc1dc7a3Sopenharmony_ci/** 1267cc1dc7a3Sopenharmony_ci * @brief Load a KTX compressed image using the local custom loader. 1268cc1dc7a3Sopenharmony_ci * 1269cc1dc7a3Sopenharmony_ci * @param filename The name of the file to load. 1270cc1dc7a3Sopenharmony_ci * @param[out] is_srgb @c true if this is an sRGB image, @c false otherwise. 1271cc1dc7a3Sopenharmony_ci * @param[out] img The output image to populate. 1272cc1dc7a3Sopenharmony_ci * 1273cc1dc7a3Sopenharmony_ci * @return @c true on error, @c false otherwise. 1274cc1dc7a3Sopenharmony_ci */ 1275cc1dc7a3Sopenharmony_cibool load_ktx_compressed_image( 1276cc1dc7a3Sopenharmony_ci const char* filename, 1277cc1dc7a3Sopenharmony_ci bool& is_srgb, 1278cc1dc7a3Sopenharmony_ci astc_compressed_image& img 1279cc1dc7a3Sopenharmony_ci) { 1280cc1dc7a3Sopenharmony_ci FILE *f = fopen(filename, "rb"); 1281cc1dc7a3Sopenharmony_ci if (!f) 1282cc1dc7a3Sopenharmony_ci { 1283cc1dc7a3Sopenharmony_ci printf("Failed to open file %s\n", filename); 1284cc1dc7a3Sopenharmony_ci return true; 1285cc1dc7a3Sopenharmony_ci } 1286cc1dc7a3Sopenharmony_ci 1287cc1dc7a3Sopenharmony_ci ktx_header hdr; 1288cc1dc7a3Sopenharmony_ci size_t actual = fread(&hdr, 1, sizeof(hdr), f); 1289cc1dc7a3Sopenharmony_ci if (actual != sizeof(hdr)) 1290cc1dc7a3Sopenharmony_ci { 1291cc1dc7a3Sopenharmony_ci printf("Failed to read header from %s\n", filename); 1292cc1dc7a3Sopenharmony_ci fclose(f); 1293cc1dc7a3Sopenharmony_ci return true; 1294cc1dc7a3Sopenharmony_ci } 1295cc1dc7a3Sopenharmony_ci 1296cc1dc7a3Sopenharmony_ci if (memcmp(hdr.magic, ktx_magic, 12) != 0 || 1297cc1dc7a3Sopenharmony_ci (hdr.endianness != 0x04030201 && hdr.endianness != 0x01020304)) 1298cc1dc7a3Sopenharmony_ci { 1299cc1dc7a3Sopenharmony_ci printf("File %s does not have a valid KTX header\n", filename); 1300cc1dc7a3Sopenharmony_ci fclose(f); 1301cc1dc7a3Sopenharmony_ci return true; 1302cc1dc7a3Sopenharmony_ci } 1303cc1dc7a3Sopenharmony_ci 1304cc1dc7a3Sopenharmony_ci bool switch_endianness = false; 1305cc1dc7a3Sopenharmony_ci if (hdr.endianness == 0x01020304) 1306cc1dc7a3Sopenharmony_ci { 1307cc1dc7a3Sopenharmony_ci switch_endianness = true; 1308cc1dc7a3Sopenharmony_ci ktx_header_switch_endianness(&hdr); 1309cc1dc7a3Sopenharmony_ci } 1310cc1dc7a3Sopenharmony_ci 1311cc1dc7a3Sopenharmony_ci if (hdr.gl_type != 0 || hdr.gl_format != 0 || hdr.gl_type_size != 1 || 1312cc1dc7a3Sopenharmony_ci hdr.gl_base_internal_format != GL_RGBA) 1313cc1dc7a3Sopenharmony_ci { 1314cc1dc7a3Sopenharmony_ci printf("File %s is not a compressed ASTC file\n", filename); 1315cc1dc7a3Sopenharmony_ci fclose(f); 1316cc1dc7a3Sopenharmony_ci return true; 1317cc1dc7a3Sopenharmony_ci } 1318cc1dc7a3Sopenharmony_ci 1319cc1dc7a3Sopenharmony_ci const format_entry* fmt = get_format(hdr.gl_internal_format); 1320cc1dc7a3Sopenharmony_ci if (!fmt) 1321cc1dc7a3Sopenharmony_ci { 1322cc1dc7a3Sopenharmony_ci printf("File %s is not a compressed ASTC file\n", filename); 1323cc1dc7a3Sopenharmony_ci fclose(f); 1324cc1dc7a3Sopenharmony_ci return true; 1325cc1dc7a3Sopenharmony_ci } 1326cc1dc7a3Sopenharmony_ci 1327cc1dc7a3Sopenharmony_ci // Skip over any key-value pairs 1328cc1dc7a3Sopenharmony_ci int seekerr; 1329cc1dc7a3Sopenharmony_ci seekerr = fseek(f, hdr.bytes_of_key_value_data, SEEK_CUR); 1330cc1dc7a3Sopenharmony_ci if (seekerr) 1331cc1dc7a3Sopenharmony_ci { 1332cc1dc7a3Sopenharmony_ci printf("Failed to skip key-value pairs in %s\n", filename); 1333cc1dc7a3Sopenharmony_ci fclose(f); 1334cc1dc7a3Sopenharmony_ci return true; 1335cc1dc7a3Sopenharmony_ci } 1336cc1dc7a3Sopenharmony_ci 1337cc1dc7a3Sopenharmony_ci // Read the length of the data and endianess convert 1338cc1dc7a3Sopenharmony_ci unsigned int data_len; 1339cc1dc7a3Sopenharmony_ci actual = fread(&data_len, 1, sizeof(data_len), f); 1340cc1dc7a3Sopenharmony_ci if (actual != sizeof(data_len)) 1341cc1dc7a3Sopenharmony_ci { 1342cc1dc7a3Sopenharmony_ci printf("Failed to read mip 0 size from %s\n", filename); 1343cc1dc7a3Sopenharmony_ci fclose(f); 1344cc1dc7a3Sopenharmony_ci return true; 1345cc1dc7a3Sopenharmony_ci } 1346cc1dc7a3Sopenharmony_ci 1347cc1dc7a3Sopenharmony_ci if (switch_endianness) 1348cc1dc7a3Sopenharmony_ci { 1349cc1dc7a3Sopenharmony_ci data_len = u32_byterev(data_len); 1350cc1dc7a3Sopenharmony_ci } 1351cc1dc7a3Sopenharmony_ci 1352cc1dc7a3Sopenharmony_ci // Read the data 1353cc1dc7a3Sopenharmony_ci unsigned char* data = new unsigned char[data_len]; 1354cc1dc7a3Sopenharmony_ci actual = fread(data, 1, data_len, f); 1355cc1dc7a3Sopenharmony_ci if (actual != data_len) 1356cc1dc7a3Sopenharmony_ci { 1357cc1dc7a3Sopenharmony_ci printf("Failed to read mip 0 data from %s\n", filename); 1358cc1dc7a3Sopenharmony_ci fclose(f); 1359cc1dc7a3Sopenharmony_ci delete[] data; 1360cc1dc7a3Sopenharmony_ci return true; 1361cc1dc7a3Sopenharmony_ci } 1362cc1dc7a3Sopenharmony_ci 1363cc1dc7a3Sopenharmony_ci img.block_x = fmt->x; 1364cc1dc7a3Sopenharmony_ci img.block_y = fmt->y; 1365cc1dc7a3Sopenharmony_ci img.block_z = fmt->z == 0 ? 1 : fmt->z; 1366cc1dc7a3Sopenharmony_ci 1367cc1dc7a3Sopenharmony_ci img.dim_x = hdr.pixel_width; 1368cc1dc7a3Sopenharmony_ci img.dim_y = hdr.pixel_height; 1369cc1dc7a3Sopenharmony_ci img.dim_z = hdr.pixel_depth == 0 ? 1 : hdr.pixel_depth; 1370cc1dc7a3Sopenharmony_ci 1371cc1dc7a3Sopenharmony_ci img.data_len = data_len; 1372cc1dc7a3Sopenharmony_ci img.data = data; 1373cc1dc7a3Sopenharmony_ci 1374cc1dc7a3Sopenharmony_ci is_srgb = fmt->is_srgb; 1375cc1dc7a3Sopenharmony_ci 1376cc1dc7a3Sopenharmony_ci fclose(f); 1377cc1dc7a3Sopenharmony_ci return false; 1378cc1dc7a3Sopenharmony_ci} 1379cc1dc7a3Sopenharmony_ci 1380cc1dc7a3Sopenharmony_ci/** 1381cc1dc7a3Sopenharmony_ci * @brief Store a KTX compressed image using a local store routine. 1382cc1dc7a3Sopenharmony_ci * 1383cc1dc7a3Sopenharmony_ci * @param img The image data to store. 1384cc1dc7a3Sopenharmony_ci * @param filename The name of the file to save. 1385cc1dc7a3Sopenharmony_ci * @param is_srgb @c true if this is an sRGB image, @c false if linear. 1386cc1dc7a3Sopenharmony_ci * 1387cc1dc7a3Sopenharmony_ci * @return @c true on error, @c false otherwise. 1388cc1dc7a3Sopenharmony_ci */ 1389cc1dc7a3Sopenharmony_cibool store_ktx_compressed_image( 1390cc1dc7a3Sopenharmony_ci const astc_compressed_image& img, 1391cc1dc7a3Sopenharmony_ci const char* filename, 1392cc1dc7a3Sopenharmony_ci bool is_srgb 1393cc1dc7a3Sopenharmony_ci) { 1394cc1dc7a3Sopenharmony_ci unsigned int fmt = get_format(img.block_x, img.block_y, img.block_z, is_srgb); 1395cc1dc7a3Sopenharmony_ci 1396cc1dc7a3Sopenharmony_ci ktx_header hdr; 1397cc1dc7a3Sopenharmony_ci memcpy(hdr.magic, ktx_magic, 12); 1398cc1dc7a3Sopenharmony_ci hdr.endianness = 0x04030201; 1399cc1dc7a3Sopenharmony_ci hdr.gl_type = 0; 1400cc1dc7a3Sopenharmony_ci hdr.gl_type_size = 1; 1401cc1dc7a3Sopenharmony_ci hdr.gl_format = 0; 1402cc1dc7a3Sopenharmony_ci hdr.gl_internal_format = fmt; 1403cc1dc7a3Sopenharmony_ci hdr.gl_base_internal_format = GL_RGBA; 1404cc1dc7a3Sopenharmony_ci hdr.pixel_width = img.dim_x; 1405cc1dc7a3Sopenharmony_ci hdr.pixel_height = img.dim_y; 1406cc1dc7a3Sopenharmony_ci hdr.pixel_depth = (img.dim_z == 1) ? 0 : img.dim_z; 1407cc1dc7a3Sopenharmony_ci hdr.number_of_array_elements = 0; 1408cc1dc7a3Sopenharmony_ci hdr.number_of_faces = 1; 1409cc1dc7a3Sopenharmony_ci hdr.number_of_mipmap_levels = 1; 1410cc1dc7a3Sopenharmony_ci hdr.bytes_of_key_value_data = 0; 1411cc1dc7a3Sopenharmony_ci 1412cc1dc7a3Sopenharmony_ci size_t expected = sizeof(ktx_header) + 4 + img.data_len; 1413cc1dc7a3Sopenharmony_ci size_t actual = 0; 1414cc1dc7a3Sopenharmony_ci 1415cc1dc7a3Sopenharmony_ci FILE *wf = fopen(filename, "wb"); 1416cc1dc7a3Sopenharmony_ci if (!wf) 1417cc1dc7a3Sopenharmony_ci { 1418cc1dc7a3Sopenharmony_ci return true; 1419cc1dc7a3Sopenharmony_ci } 1420cc1dc7a3Sopenharmony_ci 1421cc1dc7a3Sopenharmony_ci actual += fwrite(&hdr, 1, sizeof(ktx_header), wf); 1422cc1dc7a3Sopenharmony_ci actual += fwrite(&img.data_len, 1, 4, wf); 1423cc1dc7a3Sopenharmony_ci actual += fwrite(img.data, 1, img.data_len, wf); 1424cc1dc7a3Sopenharmony_ci fclose(wf); 1425cc1dc7a3Sopenharmony_ci 1426cc1dc7a3Sopenharmony_ci if (actual != expected) 1427cc1dc7a3Sopenharmony_ci { 1428cc1dc7a3Sopenharmony_ci return true; 1429cc1dc7a3Sopenharmony_ci } 1430cc1dc7a3Sopenharmony_ci 1431cc1dc7a3Sopenharmony_ci return false; 1432cc1dc7a3Sopenharmony_ci} 1433cc1dc7a3Sopenharmony_ci 1434cc1dc7a3Sopenharmony_ci/** 1435cc1dc7a3Sopenharmony_ci * @brief Save a KTX uncompressed image using a local store routine. 1436cc1dc7a3Sopenharmony_ci * 1437cc1dc7a3Sopenharmony_ci * @param img The source data for the image. 1438cc1dc7a3Sopenharmony_ci * @param filename The name of the file to save. 1439cc1dc7a3Sopenharmony_ci * @param y_flip Should the image be vertically flipped? 1440cc1dc7a3Sopenharmony_ci * 1441cc1dc7a3Sopenharmony_ci * @return @c true if the image saved OK, @c false on error. 1442cc1dc7a3Sopenharmony_ci */ 1443cc1dc7a3Sopenharmony_cistatic bool store_ktx_uncompressed_image( 1444cc1dc7a3Sopenharmony_ci const astcenc_image* img, 1445cc1dc7a3Sopenharmony_ci const char* filename, 1446cc1dc7a3Sopenharmony_ci int y_flip 1447cc1dc7a3Sopenharmony_ci) { 1448cc1dc7a3Sopenharmony_ci unsigned int dim_x = img->dim_x; 1449cc1dc7a3Sopenharmony_ci unsigned int dim_y = img->dim_y; 1450cc1dc7a3Sopenharmony_ci unsigned int dim_z = img->dim_z; 1451cc1dc7a3Sopenharmony_ci 1452cc1dc7a3Sopenharmony_ci int bitness = img->data_type == ASTCENC_TYPE_U8 ? 8 : 16; 1453cc1dc7a3Sopenharmony_ci int image_components = determine_image_components(img); 1454cc1dc7a3Sopenharmony_ci 1455cc1dc7a3Sopenharmony_ci ktx_header hdr; 1456cc1dc7a3Sopenharmony_ci 1457cc1dc7a3Sopenharmony_ci static const int gl_format_of_components[4] { 1458cc1dc7a3Sopenharmony_ci GL_RED, GL_RG, GL_RGB, GL_RGBA 1459cc1dc7a3Sopenharmony_ci }; 1460cc1dc7a3Sopenharmony_ci 1461cc1dc7a3Sopenharmony_ci static const int gl_sized_format_of_components_ldr[4] { 1462cc1dc7a3Sopenharmony_ci GL_R8, GL_RG8, GL_RGB8, GL_RGBA8 1463cc1dc7a3Sopenharmony_ci }; 1464cc1dc7a3Sopenharmony_ci 1465cc1dc7a3Sopenharmony_ci static const int gl_sized_format_of_components_hdr[4] { 1466cc1dc7a3Sopenharmony_ci GL_R16F, GL_RG16F, GL_RGB16F, GL_RGBA16F 1467cc1dc7a3Sopenharmony_ci }; 1468cc1dc7a3Sopenharmony_ci 1469cc1dc7a3Sopenharmony_ci memcpy(hdr.magic, ktx_magic, 12); 1470cc1dc7a3Sopenharmony_ci hdr.endianness = 0x04030201; 1471cc1dc7a3Sopenharmony_ci hdr.gl_type = (bitness == 16) ? GL_HALF_FLOAT : GL_UNSIGNED_BYTE; 1472cc1dc7a3Sopenharmony_ci hdr.gl_type_size = bitness / 8; 1473cc1dc7a3Sopenharmony_ci hdr.gl_format = gl_format_of_components[image_components - 1]; 1474cc1dc7a3Sopenharmony_ci if (bitness == 16) 1475cc1dc7a3Sopenharmony_ci { 1476cc1dc7a3Sopenharmony_ci hdr.gl_internal_format = gl_sized_format_of_components_hdr[image_components - 1]; 1477cc1dc7a3Sopenharmony_ci } 1478cc1dc7a3Sopenharmony_ci else 1479cc1dc7a3Sopenharmony_ci { 1480cc1dc7a3Sopenharmony_ci hdr.gl_internal_format = gl_sized_format_of_components_ldr[image_components - 1]; 1481cc1dc7a3Sopenharmony_ci } 1482cc1dc7a3Sopenharmony_ci hdr.gl_base_internal_format = hdr.gl_format; 1483cc1dc7a3Sopenharmony_ci hdr.pixel_width = dim_x; 1484cc1dc7a3Sopenharmony_ci hdr.pixel_height = dim_y; 1485cc1dc7a3Sopenharmony_ci hdr.pixel_depth = (dim_z == 1) ? 0 : dim_z; 1486cc1dc7a3Sopenharmony_ci hdr.number_of_array_elements = 0; 1487cc1dc7a3Sopenharmony_ci hdr.number_of_faces = 1; 1488cc1dc7a3Sopenharmony_ci hdr.number_of_mipmap_levels = 1; 1489cc1dc7a3Sopenharmony_ci hdr.bytes_of_key_value_data = 0; 1490cc1dc7a3Sopenharmony_ci 1491cc1dc7a3Sopenharmony_ci // Collect image data to write 1492cc1dc7a3Sopenharmony_ci uint8_t ***row_pointers8 = nullptr; 1493cc1dc7a3Sopenharmony_ci uint16_t ***row_pointers16 = nullptr; 1494cc1dc7a3Sopenharmony_ci if (bitness == 8) 1495cc1dc7a3Sopenharmony_ci { 1496cc1dc7a3Sopenharmony_ci row_pointers8 = new uint8_t **[dim_z]; 1497cc1dc7a3Sopenharmony_ci row_pointers8[0] = new uint8_t *[dim_y * dim_z]; 1498cc1dc7a3Sopenharmony_ci row_pointers8[0][0] = new uint8_t[dim_x * dim_y * dim_z * image_components + 3]; 1499cc1dc7a3Sopenharmony_ci 1500cc1dc7a3Sopenharmony_ci for (unsigned int z = 1; z < dim_z; z++) 1501cc1dc7a3Sopenharmony_ci { 1502cc1dc7a3Sopenharmony_ci row_pointers8[z] = row_pointers8[0] + dim_y * z; 1503cc1dc7a3Sopenharmony_ci row_pointers8[z][0] = row_pointers8[0][0] + dim_y * dim_x * image_components * z; 1504cc1dc7a3Sopenharmony_ci } 1505cc1dc7a3Sopenharmony_ci 1506cc1dc7a3Sopenharmony_ci for (unsigned int z = 0; z < dim_z; z++) 1507cc1dc7a3Sopenharmony_ci { 1508cc1dc7a3Sopenharmony_ci for (unsigned int y = 1; y < dim_y; y++) 1509cc1dc7a3Sopenharmony_ci { 1510cc1dc7a3Sopenharmony_ci row_pointers8[z][y] = row_pointers8[z][0] + dim_x * image_components * y; 1511cc1dc7a3Sopenharmony_ci } 1512cc1dc7a3Sopenharmony_ci } 1513cc1dc7a3Sopenharmony_ci 1514cc1dc7a3Sopenharmony_ci for (unsigned int z = 0; z < dim_z; z++) 1515cc1dc7a3Sopenharmony_ci { 1516cc1dc7a3Sopenharmony_ci uint8_t* data8 = static_cast<uint8_t*>(img->data[z]); 1517cc1dc7a3Sopenharmony_ci for (unsigned int y = 0; y < dim_y; y++) 1518cc1dc7a3Sopenharmony_ci { 1519cc1dc7a3Sopenharmony_ci int ym = y_flip ? dim_y - y - 1 : y; 1520cc1dc7a3Sopenharmony_ci switch (image_components) 1521cc1dc7a3Sopenharmony_ci { 1522cc1dc7a3Sopenharmony_ci case 1: // single-component, treated as Luminance 1523cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 1524cc1dc7a3Sopenharmony_ci { 1525cc1dc7a3Sopenharmony_ci row_pointers8[z][y][x] = data8[(4 * dim_x * ym) + (4 * x )]; 1526cc1dc7a3Sopenharmony_ci } 1527cc1dc7a3Sopenharmony_ci break; 1528cc1dc7a3Sopenharmony_ci case 2: // two-component, treated as Luminance-Alpha 1529cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 1530cc1dc7a3Sopenharmony_ci { 1531cc1dc7a3Sopenharmony_ci row_pointers8[z][y][2 * x ] = data8[(4 * dim_x * ym) + (4 * x )]; 1532cc1dc7a3Sopenharmony_ci row_pointers8[z][y][2 * x + 1] = data8[(4 * dim_x * ym) + (4 * x + 3)]; 1533cc1dc7a3Sopenharmony_ci } 1534cc1dc7a3Sopenharmony_ci break; 1535cc1dc7a3Sopenharmony_ci case 3: // three-component, treated a 1536cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 1537cc1dc7a3Sopenharmony_ci { 1538cc1dc7a3Sopenharmony_ci row_pointers8[z][y][3 * x ] = data8[(4 * dim_x * ym) + (4 * x )]; 1539cc1dc7a3Sopenharmony_ci row_pointers8[z][y][3 * x + 1] = data8[(4 * dim_x * ym) + (4 * x + 1)]; 1540cc1dc7a3Sopenharmony_ci row_pointers8[z][y][3 * x + 2] = data8[(4 * dim_x * ym) + (4 * x + 2)]; 1541cc1dc7a3Sopenharmony_ci } 1542cc1dc7a3Sopenharmony_ci break; 1543cc1dc7a3Sopenharmony_ci case 4: // four-component, treated as RGBA 1544cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 1545cc1dc7a3Sopenharmony_ci { 1546cc1dc7a3Sopenharmony_ci row_pointers8[z][y][4 * x ] = data8[(4 * dim_x * ym) + (4 * x )]; 1547cc1dc7a3Sopenharmony_ci row_pointers8[z][y][4 * x + 1] = data8[(4 * dim_x * ym) + (4 * x + 1)]; 1548cc1dc7a3Sopenharmony_ci row_pointers8[z][y][4 * x + 2] = data8[(4 * dim_x * ym) + (4 * x + 2)]; 1549cc1dc7a3Sopenharmony_ci row_pointers8[z][y][4 * x + 3] = data8[(4 * dim_x * ym) + (4 * x + 3)]; 1550cc1dc7a3Sopenharmony_ci } 1551cc1dc7a3Sopenharmony_ci break; 1552cc1dc7a3Sopenharmony_ci } 1553cc1dc7a3Sopenharmony_ci } 1554cc1dc7a3Sopenharmony_ci } 1555cc1dc7a3Sopenharmony_ci } 1556cc1dc7a3Sopenharmony_ci else // if bitness == 16 1557cc1dc7a3Sopenharmony_ci { 1558cc1dc7a3Sopenharmony_ci row_pointers16 = new uint16_t **[dim_z]; 1559cc1dc7a3Sopenharmony_ci row_pointers16[0] = new uint16_t *[dim_y * dim_z]; 1560cc1dc7a3Sopenharmony_ci row_pointers16[0][0] = new uint16_t[dim_x * dim_y * dim_z * image_components + 1]; 1561cc1dc7a3Sopenharmony_ci 1562cc1dc7a3Sopenharmony_ci for (unsigned int z = 1; z < dim_z; z++) 1563cc1dc7a3Sopenharmony_ci { 1564cc1dc7a3Sopenharmony_ci row_pointers16[z] = row_pointers16[0] + dim_y * z; 1565cc1dc7a3Sopenharmony_ci row_pointers16[z][0] = row_pointers16[0][0] + dim_y * dim_x * image_components * z; 1566cc1dc7a3Sopenharmony_ci } 1567cc1dc7a3Sopenharmony_ci 1568cc1dc7a3Sopenharmony_ci for (unsigned int z = 0; z < dim_z; z++) 1569cc1dc7a3Sopenharmony_ci { 1570cc1dc7a3Sopenharmony_ci for (unsigned int y = 1; y < dim_y; y++) 1571cc1dc7a3Sopenharmony_ci { 1572cc1dc7a3Sopenharmony_ci row_pointers16[z][y] = row_pointers16[z][0] + dim_x * image_components * y; 1573cc1dc7a3Sopenharmony_ci } 1574cc1dc7a3Sopenharmony_ci } 1575cc1dc7a3Sopenharmony_ci 1576cc1dc7a3Sopenharmony_ci for (unsigned int z = 0; z < dim_z; z++) 1577cc1dc7a3Sopenharmony_ci { 1578cc1dc7a3Sopenharmony_ci uint16_t* data16 = static_cast<uint16_t*>(img->data[z]); 1579cc1dc7a3Sopenharmony_ci for (unsigned int y = 0; y < dim_y; y++) 1580cc1dc7a3Sopenharmony_ci { 1581cc1dc7a3Sopenharmony_ci int ym = y_flip ? dim_y - y - 1 : y; 1582cc1dc7a3Sopenharmony_ci switch (image_components) 1583cc1dc7a3Sopenharmony_ci { 1584cc1dc7a3Sopenharmony_ci case 1: // single-component, treated as Luminance 1585cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 1586cc1dc7a3Sopenharmony_ci { 1587cc1dc7a3Sopenharmony_ci row_pointers16[z][y][x] = data16[(4 * dim_x * ym) + (4 * x )]; 1588cc1dc7a3Sopenharmony_ci } 1589cc1dc7a3Sopenharmony_ci break; 1590cc1dc7a3Sopenharmony_ci case 2: // two-component, treated as Luminance-Alpha 1591cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 1592cc1dc7a3Sopenharmony_ci { 1593cc1dc7a3Sopenharmony_ci row_pointers16[z][y][2 * x ] = data16[(4 * dim_x * ym) + (4 * x )]; 1594cc1dc7a3Sopenharmony_ci row_pointers16[z][y][2 * x + 1] = data16[(4 * dim_x * ym) + (4 * x + 3)]; 1595cc1dc7a3Sopenharmony_ci } 1596cc1dc7a3Sopenharmony_ci break; 1597cc1dc7a3Sopenharmony_ci case 3: // three-component, treated as RGB 1598cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 1599cc1dc7a3Sopenharmony_ci { 1600cc1dc7a3Sopenharmony_ci row_pointers16[z][y][3 * x ] = data16[(4 * dim_x * ym) + (4 * x )]; 1601cc1dc7a3Sopenharmony_ci row_pointers16[z][y][3 * x + 1] = data16[(4 * dim_x * ym) + (4 * x + 1)]; 1602cc1dc7a3Sopenharmony_ci row_pointers16[z][y][3 * x + 2] = data16[(4 * dim_x * ym) + (4 * x + 2)]; 1603cc1dc7a3Sopenharmony_ci } 1604cc1dc7a3Sopenharmony_ci break; 1605cc1dc7a3Sopenharmony_ci case 4: // four-component, treated as RGBA 1606cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 1607cc1dc7a3Sopenharmony_ci { 1608cc1dc7a3Sopenharmony_ci row_pointers16[z][y][4 * x ] = data16[(4 * dim_x * ym) + (4 * x )]; 1609cc1dc7a3Sopenharmony_ci row_pointers16[z][y][4 * x + 1] = data16[(4 * dim_x * ym) + (4 * x + 1)]; 1610cc1dc7a3Sopenharmony_ci row_pointers16[z][y][4 * x + 2] = data16[(4 * dim_x * ym) + (4 * x + 2)]; 1611cc1dc7a3Sopenharmony_ci row_pointers16[z][y][4 * x + 3] = data16[(4 * dim_x * ym) + (4 * x + 3)]; 1612cc1dc7a3Sopenharmony_ci } 1613cc1dc7a3Sopenharmony_ci break; 1614cc1dc7a3Sopenharmony_ci } 1615cc1dc7a3Sopenharmony_ci } 1616cc1dc7a3Sopenharmony_ci } 1617cc1dc7a3Sopenharmony_ci } 1618cc1dc7a3Sopenharmony_ci 1619cc1dc7a3Sopenharmony_ci bool retval { true }; 1620cc1dc7a3Sopenharmony_ci uint32_t image_bytes = dim_x * dim_y * dim_z * image_components * (bitness / 8); 1621cc1dc7a3Sopenharmony_ci uint32_t image_write_bytes = (image_bytes + 3) & ~3; 1622cc1dc7a3Sopenharmony_ci 1623cc1dc7a3Sopenharmony_ci FILE *wf = fopen(filename, "wb"); 1624cc1dc7a3Sopenharmony_ci if (wf) 1625cc1dc7a3Sopenharmony_ci { 1626cc1dc7a3Sopenharmony_ci void* dataptr = (bitness == 16) ? 1627cc1dc7a3Sopenharmony_ci reinterpret_cast<void*>(row_pointers16[0][0]) : 1628cc1dc7a3Sopenharmony_ci reinterpret_cast<void*>(row_pointers8[0][0]); 1629cc1dc7a3Sopenharmony_ci 1630cc1dc7a3Sopenharmony_ci size_t expected_bytes_written = sizeof(ktx_header) + image_write_bytes + 4; 1631cc1dc7a3Sopenharmony_ci size_t hdr_bytes_written = fwrite(&hdr, 1, sizeof(ktx_header), wf); 1632cc1dc7a3Sopenharmony_ci size_t bytecount_bytes_written = fwrite(&image_bytes, 1, 4, wf); 1633cc1dc7a3Sopenharmony_ci size_t data_bytes_written = fwrite(dataptr, 1, image_write_bytes, wf); 1634cc1dc7a3Sopenharmony_ci fclose(wf); 1635cc1dc7a3Sopenharmony_ci if (hdr_bytes_written + bytecount_bytes_written + data_bytes_written != expected_bytes_written) 1636cc1dc7a3Sopenharmony_ci { 1637cc1dc7a3Sopenharmony_ci retval = false; 1638cc1dc7a3Sopenharmony_ci } 1639cc1dc7a3Sopenharmony_ci } 1640cc1dc7a3Sopenharmony_ci else 1641cc1dc7a3Sopenharmony_ci { 1642cc1dc7a3Sopenharmony_ci retval = false; 1643cc1dc7a3Sopenharmony_ci } 1644cc1dc7a3Sopenharmony_ci 1645cc1dc7a3Sopenharmony_ci if (row_pointers8) 1646cc1dc7a3Sopenharmony_ci { 1647cc1dc7a3Sopenharmony_ci delete[] row_pointers8[0][0]; 1648cc1dc7a3Sopenharmony_ci delete[] row_pointers8[0]; 1649cc1dc7a3Sopenharmony_ci delete[] row_pointers8; 1650cc1dc7a3Sopenharmony_ci } 1651cc1dc7a3Sopenharmony_ci 1652cc1dc7a3Sopenharmony_ci if (row_pointers16) 1653cc1dc7a3Sopenharmony_ci { 1654cc1dc7a3Sopenharmony_ci delete[] row_pointers16[0][0]; 1655cc1dc7a3Sopenharmony_ci delete[] row_pointers16[0]; 1656cc1dc7a3Sopenharmony_ci delete[] row_pointers16; 1657cc1dc7a3Sopenharmony_ci } 1658cc1dc7a3Sopenharmony_ci 1659cc1dc7a3Sopenharmony_ci return retval; 1660cc1dc7a3Sopenharmony_ci} 1661cc1dc7a3Sopenharmony_ci 1662cc1dc7a3Sopenharmony_ci/* 1663cc1dc7a3Sopenharmony_ci Loader for DDS files. 1664cc1dc7a3Sopenharmony_ci 1665cc1dc7a3Sopenharmony_ci Note that after the header, data are densely packed with no padding; 1666cc1dc7a3Sopenharmony_ci in the case of multiple surfaces, they appear one after another in 1667cc1dc7a3Sopenharmony_ci the file, again with no padding. 1668cc1dc7a3Sopenharmony_ci 1669cc1dc7a3Sopenharmony_ci This code is NOT endian-neutral. 1670cc1dc7a3Sopenharmony_ci*/ 1671cc1dc7a3Sopenharmony_cistruct dds_pixelformat 1672cc1dc7a3Sopenharmony_ci{ 1673cc1dc7a3Sopenharmony_ci uint32_t size; // structure size, set to 32. 1674cc1dc7a3Sopenharmony_ci /* 1675cc1dc7a3Sopenharmony_ci flags bits are a combination of the following: 0x1 : Texture contains alpha data 0x2 : ---- (older files: texture contains alpha data, for Alpha-only texture) 0x4 : The fourcc field is valid, 1676cc1dc7a3Sopenharmony_ci indicating a compressed or DX10 texture format 0x40 : texture contains uncompressed RGB data 0x200 : ---- (YUV in older files) 0x20000 : Texture contains Luminance data (can be combined with 1677cc1dc7a3Sopenharmony_ci 0x1 for Lum-Alpha) */ 1678cc1dc7a3Sopenharmony_ci uint32_t flags; 1679cc1dc7a3Sopenharmony_ci uint32_t fourcc; // "DX10" to indicate a DX10 format, "DXTn" for the DXT formats 1680cc1dc7a3Sopenharmony_ci uint32_t rgbbitcount; // number of bits per texel; up to 32 for non-DX10 formats. 1681cc1dc7a3Sopenharmony_ci uint32_t rbitmask; // bitmap indicating position of red/luminance color component 1682cc1dc7a3Sopenharmony_ci uint32_t gbitmask; // bitmap indicating position of green color component 1683cc1dc7a3Sopenharmony_ci uint32_t bbitmask; // bitmap indicating position of blue color component 1684cc1dc7a3Sopenharmony_ci uint32_t abitmask; // bitmap indicating position of alpha color component 1685cc1dc7a3Sopenharmony_ci}; 1686cc1dc7a3Sopenharmony_ci 1687cc1dc7a3Sopenharmony_cistruct dds_header 1688cc1dc7a3Sopenharmony_ci{ 1689cc1dc7a3Sopenharmony_ci uint32_t size; // header size; must be exactly 124. 1690cc1dc7a3Sopenharmony_ci /* 1691cc1dc7a3Sopenharmony_ci flag field is an OR or the following bits, that indicate fields containing valid data: 1692cc1dc7a3Sopenharmony_ci 1: caps/caps2/caps3/caps4 (set in all DDS files, ignore on read) 1693cc1dc7a3Sopenharmony_ci 2: height (set in all DDS files, ignore on read) 1694cc1dc7a3Sopenharmony_ci 4: width (set in all DDS files, ignore on read) 1695cc1dc7a3Sopenharmony_ci 8: pitch (for uncompressed texture) 1696cc1dc7a3Sopenharmony_ci 0x1000: the pixel format field (set in all DDS files, ignore on read) 1697cc1dc7a3Sopenharmony_ci 0x20000: mipmap count (for mipmapped textures with >1 level) 1698cc1dc7a3Sopenharmony_ci 0x80000: pitch (for compressed texture) 1699cc1dc7a3Sopenharmony_ci 0x800000: depth (for 3d textures) 1700cc1dc7a3Sopenharmony_ci */ 1701cc1dc7a3Sopenharmony_ci uint32_t flags; 1702cc1dc7a3Sopenharmony_ci uint32_t height; 1703cc1dc7a3Sopenharmony_ci uint32_t width; 1704cc1dc7a3Sopenharmony_ci uint32_t pitch_or_linear_size; // scanline pitch for uncompressed; total size in bytes for compressed 1705cc1dc7a3Sopenharmony_ci uint32_t depth; 1706cc1dc7a3Sopenharmony_ci uint32_t mipmapcount; 1707cc1dc7a3Sopenharmony_ci // unused, set to 0 1708cc1dc7a3Sopenharmony_ci uint32_t reserved1[11]; 1709cc1dc7a3Sopenharmony_ci dds_pixelformat ddspf; 1710cc1dc7a3Sopenharmony_ci /* 1711cc1dc7a3Sopenharmony_ci caps field is an OR of the following values: 1712cc1dc7a3Sopenharmony_ci 8 : should be set for a file that contains more than 1 surface (ignore on read) 1713cc1dc7a3Sopenharmony_ci 0x400000 : should be set for a mipmapped texture 1714cc1dc7a3Sopenharmony_ci 0x1000 : should be set if the surface is a texture at all (all DDS files, ignore on read) 1715cc1dc7a3Sopenharmony_ci */ 1716cc1dc7a3Sopenharmony_ci uint32_t caps; 1717cc1dc7a3Sopenharmony_ci /* 1718cc1dc7a3Sopenharmony_ci caps2 field is an OR of the following values: 1719cc1dc7a3Sopenharmony_ci 0x200 : texture is cubemap 1720cc1dc7a3Sopenharmony_ci 0x400 : +X face of cubemap is present 1721cc1dc7a3Sopenharmony_ci 0x800 : -X face of cubemap is present 1722cc1dc7a3Sopenharmony_ci 0x1000 : +Y face of cubemap is present 1723cc1dc7a3Sopenharmony_ci 0x2000 : -Y face of cubemap is present 1724cc1dc7a3Sopenharmony_ci 0x4000 : +Z face of cubemap is present 1725cc1dc7a3Sopenharmony_ci 0x8000 : -Z face of cubemap is present 1726cc1dc7a3Sopenharmony_ci 0x200000 : texture is a 3d texture. 1727cc1dc7a3Sopenharmony_ci */ 1728cc1dc7a3Sopenharmony_ci uint32_t caps2; 1729cc1dc7a3Sopenharmony_ci // unused, set to 0 1730cc1dc7a3Sopenharmony_ci uint32_t caps3; 1731cc1dc7a3Sopenharmony_ci // unused, set to 0 1732cc1dc7a3Sopenharmony_ci uint32_t caps4; 1733cc1dc7a3Sopenharmony_ci // unused, set to 0 1734cc1dc7a3Sopenharmony_ci uint32_t reserved2; 1735cc1dc7a3Sopenharmony_ci}; 1736cc1dc7a3Sopenharmony_ci 1737cc1dc7a3Sopenharmony_cistruct dds_header_dx10 1738cc1dc7a3Sopenharmony_ci{ 1739cc1dc7a3Sopenharmony_ci uint32_t dxgi_format; 1740cc1dc7a3Sopenharmony_ci uint32_t resource_dimension; // 2=1d-texture, 3=2d-texture or cubemap, 4=3d-texture 1741cc1dc7a3Sopenharmony_ci uint32_t misc_flag; // 4 if cubemap, else 0 1742cc1dc7a3Sopenharmony_ci uint32_t array_size; // size of array in case of a texture array; set to 1 for a non-array 1743cc1dc7a3Sopenharmony_ci uint32_t reserved; // set to 0. 1744cc1dc7a3Sopenharmony_ci}; 1745cc1dc7a3Sopenharmony_ci 1746cc1dc7a3Sopenharmony_ci#define DDS_MAGIC 0x20534444 1747cc1dc7a3Sopenharmony_ci#define DX10_MAGIC 0x30315844 1748cc1dc7a3Sopenharmony_ci 1749cc1dc7a3Sopenharmony_ci/** 1750cc1dc7a3Sopenharmony_ci * @brief Load an uncompressed DDS image using the local custom loader. 1751cc1dc7a3Sopenharmony_ci * 1752cc1dc7a3Sopenharmony_ci * @param filename The name of the file to load. 1753cc1dc7a3Sopenharmony_ci * @param y_flip Should the image be vertically flipped? 1754cc1dc7a3Sopenharmony_ci * @param[out] is_hdr Is this an HDR image load? 1755cc1dc7a3Sopenharmony_ci * @param[out] component_count The number of components in the data. 1756cc1dc7a3Sopenharmony_ci * 1757cc1dc7a3Sopenharmony_ci * @return The loaded image data in a canonical 4 channel format, or @c nullptr on error. 1758cc1dc7a3Sopenharmony_ci */ 1759cc1dc7a3Sopenharmony_cistatic astcenc_image* load_dds_uncompressed_image( 1760cc1dc7a3Sopenharmony_ci const char* filename, 1761cc1dc7a3Sopenharmony_ci bool y_flip, 1762cc1dc7a3Sopenharmony_ci bool& is_hdr, 1763cc1dc7a3Sopenharmony_ci unsigned int& component_count 1764cc1dc7a3Sopenharmony_ci) { 1765cc1dc7a3Sopenharmony_ci FILE *f = fopen(filename, "rb"); 1766cc1dc7a3Sopenharmony_ci if (!f) 1767cc1dc7a3Sopenharmony_ci { 1768cc1dc7a3Sopenharmony_ci printf("Failed to open file %s\n", filename); 1769cc1dc7a3Sopenharmony_ci return nullptr; 1770cc1dc7a3Sopenharmony_ci } 1771cc1dc7a3Sopenharmony_ci 1772cc1dc7a3Sopenharmony_ci uint8_t magic[4]; 1773cc1dc7a3Sopenharmony_ci 1774cc1dc7a3Sopenharmony_ci dds_header hdr; 1775cc1dc7a3Sopenharmony_ci size_t magic_bytes_read = fread(magic, 1, 4, f); 1776cc1dc7a3Sopenharmony_ci size_t header_bytes_read = fread(&hdr, 1, sizeof(hdr), f); 1777cc1dc7a3Sopenharmony_ci if (magic_bytes_read != 4 || header_bytes_read != sizeof(hdr)) 1778cc1dc7a3Sopenharmony_ci { 1779cc1dc7a3Sopenharmony_ci printf("Failed to read header of DDS file %s\n", filename); 1780cc1dc7a3Sopenharmony_ci fclose(f); 1781cc1dc7a3Sopenharmony_ci return nullptr; 1782cc1dc7a3Sopenharmony_ci } 1783cc1dc7a3Sopenharmony_ci 1784cc1dc7a3Sopenharmony_ci uint32_t magicx = magic[0] | (magic[1] << 8) | (magic[2] << 16) | (magic[3] << 24); 1785cc1dc7a3Sopenharmony_ci 1786cc1dc7a3Sopenharmony_ci if (magicx != DDS_MAGIC || hdr.size != 124) 1787cc1dc7a3Sopenharmony_ci { 1788cc1dc7a3Sopenharmony_ci printf("File %s does not have a valid DDS header\n", filename); 1789cc1dc7a3Sopenharmony_ci fclose(f); 1790cc1dc7a3Sopenharmony_ci return nullptr; 1791cc1dc7a3Sopenharmony_ci } 1792cc1dc7a3Sopenharmony_ci 1793cc1dc7a3Sopenharmony_ci int use_dx10_header = 0; 1794cc1dc7a3Sopenharmony_ci if (hdr.ddspf.flags & 4) 1795cc1dc7a3Sopenharmony_ci { 1796cc1dc7a3Sopenharmony_ci if (hdr.ddspf.fourcc == DX10_MAGIC) 1797cc1dc7a3Sopenharmony_ci { 1798cc1dc7a3Sopenharmony_ci use_dx10_header = 1; 1799cc1dc7a3Sopenharmony_ci } 1800cc1dc7a3Sopenharmony_ci else 1801cc1dc7a3Sopenharmony_ci { 1802cc1dc7a3Sopenharmony_ci printf("DDS file %s is compressed, not supported\n", filename); 1803cc1dc7a3Sopenharmony_ci fclose(f); 1804cc1dc7a3Sopenharmony_ci return nullptr; 1805cc1dc7a3Sopenharmony_ci } 1806cc1dc7a3Sopenharmony_ci } 1807cc1dc7a3Sopenharmony_ci 1808cc1dc7a3Sopenharmony_ci dds_header_dx10 dx10_header; 1809cc1dc7a3Sopenharmony_ci if (use_dx10_header) 1810cc1dc7a3Sopenharmony_ci { 1811cc1dc7a3Sopenharmony_ci size_t dx10_header_bytes_read = fread(&dx10_header, 1, sizeof(dx10_header), f); 1812cc1dc7a3Sopenharmony_ci if (dx10_header_bytes_read != sizeof(dx10_header)) 1813cc1dc7a3Sopenharmony_ci { 1814cc1dc7a3Sopenharmony_ci printf("Failed to read header of DDS file %s\n", filename); 1815cc1dc7a3Sopenharmony_ci fclose(f); 1816cc1dc7a3Sopenharmony_ci return nullptr; 1817cc1dc7a3Sopenharmony_ci } 1818cc1dc7a3Sopenharmony_ci } 1819cc1dc7a3Sopenharmony_ci 1820cc1dc7a3Sopenharmony_ci unsigned int dim_x = hdr.width; 1821cc1dc7a3Sopenharmony_ci unsigned int dim_y = hdr.height; 1822cc1dc7a3Sopenharmony_ci unsigned int dim_z = (hdr.flags & 0x800000) ? hdr.depth : 1; 1823cc1dc7a3Sopenharmony_ci 1824cc1dc7a3Sopenharmony_ci // The bitcount that we will use internally in the codec 1825cc1dc7a3Sopenharmony_ci int bitness = 0; 1826cc1dc7a3Sopenharmony_ci 1827cc1dc7a3Sopenharmony_ci // The bytes per component in the DDS file itself 1828cc1dc7a3Sopenharmony_ci int bytes_per_component = 0; 1829cc1dc7a3Sopenharmony_ci int components = 0; 1830cc1dc7a3Sopenharmony_ci scanline_transfer copy_method = R8_TO_RGBA8; 1831cc1dc7a3Sopenharmony_ci 1832cc1dc7a3Sopenharmony_ci // figure out the format actually used in the DDS file. 1833cc1dc7a3Sopenharmony_ci if (use_dx10_header) 1834cc1dc7a3Sopenharmony_ci { 1835cc1dc7a3Sopenharmony_ci // DX10 header present; use the DXGI format. 1836cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_R32G32B32A32_FLOAT 2 1837cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_R32G32B32_FLOAT 6 1838cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_R16G16B16A16_FLOAT 10 1839cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_R16G16B16A16_UNORM 11 1840cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_R32G32_FLOAT 16 1841cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_R8G8B8A8_UNORM 28 1842cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_R16G16_FLOAT 34 1843cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_R16G16_UNORM 35 1844cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_R32_FLOAT 41 1845cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_R8G8_UNORM 49 1846cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_R16_FLOAT 54 1847cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_R16_UNORM 56 1848cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_R8_UNORM 61 1849cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_B8G8R8A8_UNORM 86 1850cc1dc7a3Sopenharmony_ci #define DXGI_FORMAT_B8G8R8X8_UNORM 87 1851cc1dc7a3Sopenharmony_ci 1852cc1dc7a3Sopenharmony_ci struct dxgi_params 1853cc1dc7a3Sopenharmony_ci { 1854cc1dc7a3Sopenharmony_ci int bitness; 1855cc1dc7a3Sopenharmony_ci int bytes_per_component; 1856cc1dc7a3Sopenharmony_ci int components; 1857cc1dc7a3Sopenharmony_ci scanline_transfer copy_method; 1858cc1dc7a3Sopenharmony_ci uint32_t dxgi_format_number; 1859cc1dc7a3Sopenharmony_ci }; 1860cc1dc7a3Sopenharmony_ci 1861cc1dc7a3Sopenharmony_ci static const dxgi_params format_params[] { 1862cc1dc7a3Sopenharmony_ci {16, 4, 4, RGBA32F_TO_RGBA16F, DXGI_FORMAT_R32G32B32A32_FLOAT}, 1863cc1dc7a3Sopenharmony_ci {16, 4, 3, RGB32F_TO_RGBA16F, DXGI_FORMAT_R32G32B32_FLOAT}, 1864cc1dc7a3Sopenharmony_ci {16, 2, 4, RGBA16F_TO_RGBA16F, DXGI_FORMAT_R16G16B16A16_FLOAT}, 1865cc1dc7a3Sopenharmony_ci {16, 2, 4, RGBA16_TO_RGBA16F, DXGI_FORMAT_R16G16B16A16_UNORM}, 1866cc1dc7a3Sopenharmony_ci {16, 4, 2, RG32F_TO_RGBA16F, DXGI_FORMAT_R32G32_FLOAT}, 1867cc1dc7a3Sopenharmony_ci {8, 1, 4, RGBA8_TO_RGBA8, DXGI_FORMAT_R8G8B8A8_UNORM}, 1868cc1dc7a3Sopenharmony_ci {16, 2, 2, RG16F_TO_RGBA16F, DXGI_FORMAT_R16G16_FLOAT}, 1869cc1dc7a3Sopenharmony_ci {16, 2, 2, RG16_TO_RGBA16F, DXGI_FORMAT_R16G16_UNORM}, 1870cc1dc7a3Sopenharmony_ci {16, 4, 1, R32F_TO_RGBA16F, DXGI_FORMAT_R32_FLOAT}, 1871cc1dc7a3Sopenharmony_ci {8, 1, 2, RG8_TO_RGBA8, DXGI_FORMAT_R8G8_UNORM}, 1872cc1dc7a3Sopenharmony_ci {16, 2, 1, R16F_TO_RGBA16F, DXGI_FORMAT_R16_FLOAT}, 1873cc1dc7a3Sopenharmony_ci {16, 2, 1, R16_TO_RGBA16F, DXGI_FORMAT_R16_UNORM}, 1874cc1dc7a3Sopenharmony_ci {8, 1, 1, R8_TO_RGBA8, DXGI_FORMAT_R8_UNORM}, 1875cc1dc7a3Sopenharmony_ci {8, 1, 4, BGRA8_TO_RGBA8, DXGI_FORMAT_B8G8R8A8_UNORM}, 1876cc1dc7a3Sopenharmony_ci {8, 1, 4, BGRX8_TO_RGBA8, DXGI_FORMAT_B8G8R8X8_UNORM}, 1877cc1dc7a3Sopenharmony_ci }; 1878cc1dc7a3Sopenharmony_ci 1879cc1dc7a3Sopenharmony_ci int dxgi_modes_supported = sizeof(format_params) / sizeof(format_params[0]); 1880cc1dc7a3Sopenharmony_ci int did_select_format = 0; 1881cc1dc7a3Sopenharmony_ci for (int i = 0; i < dxgi_modes_supported; i++) 1882cc1dc7a3Sopenharmony_ci { 1883cc1dc7a3Sopenharmony_ci if (dx10_header.dxgi_format == format_params[i].dxgi_format_number) 1884cc1dc7a3Sopenharmony_ci { 1885cc1dc7a3Sopenharmony_ci bitness = format_params[i].bitness; 1886cc1dc7a3Sopenharmony_ci bytes_per_component = format_params[i].bytes_per_component; 1887cc1dc7a3Sopenharmony_ci components = format_params[i].components; 1888cc1dc7a3Sopenharmony_ci copy_method = format_params[i].copy_method; 1889cc1dc7a3Sopenharmony_ci did_select_format = 1; 1890cc1dc7a3Sopenharmony_ci break; 1891cc1dc7a3Sopenharmony_ci } 1892cc1dc7a3Sopenharmony_ci } 1893cc1dc7a3Sopenharmony_ci 1894cc1dc7a3Sopenharmony_ci if (!did_select_format) 1895cc1dc7a3Sopenharmony_ci { 1896cc1dc7a3Sopenharmony_ci printf("DDS file %s: DXGI format not supported by codec\n", filename); 1897cc1dc7a3Sopenharmony_ci fclose(f); 1898cc1dc7a3Sopenharmony_ci return nullptr; 1899cc1dc7a3Sopenharmony_ci } 1900cc1dc7a3Sopenharmony_ci } 1901cc1dc7a3Sopenharmony_ci else 1902cc1dc7a3Sopenharmony_ci { 1903cc1dc7a3Sopenharmony_ci // No DX10 header present. Then try to match the bitcount and bitmask against 1904cc1dc7a3Sopenharmony_ci // a set of prepared patterns. 1905cc1dc7a3Sopenharmony_ci uint32_t flags = hdr.ddspf.flags; 1906cc1dc7a3Sopenharmony_ci uint32_t bitcount = hdr.ddspf.rgbbitcount; 1907cc1dc7a3Sopenharmony_ci uint32_t rmask = hdr.ddspf.rbitmask; 1908cc1dc7a3Sopenharmony_ci uint32_t gmask = hdr.ddspf.gbitmask; 1909cc1dc7a3Sopenharmony_ci uint32_t bmask = hdr.ddspf.bbitmask; 1910cc1dc7a3Sopenharmony_ci uint32_t amask = hdr.ddspf.abitmask; 1911cc1dc7a3Sopenharmony_ci 1912cc1dc7a3Sopenharmony_ci // RGBA-unorm8 1913cc1dc7a3Sopenharmony_ci if ((flags & 0x41) == 0x41 && bitcount == 32 && rmask == 0xFF && gmask == 0xFF00 && bmask == 0xFF0000 && amask == 0xFF000000) 1914cc1dc7a3Sopenharmony_ci { 1915cc1dc7a3Sopenharmony_ci bytes_per_component = 1; 1916cc1dc7a3Sopenharmony_ci components = 4; 1917cc1dc7a3Sopenharmony_ci copy_method = RGBA8_TO_RGBA8; 1918cc1dc7a3Sopenharmony_ci } 1919cc1dc7a3Sopenharmony_ci // BGRA-unorm8 1920cc1dc7a3Sopenharmony_ci else if ((flags & 0x41) == 0x41 && bitcount == 32 && rmask == 0xFF0000 && gmask == 0xFF00 && bmask == 0xFF && amask == 0xFF000000) 1921cc1dc7a3Sopenharmony_ci { 1922cc1dc7a3Sopenharmony_ci bytes_per_component = 1; 1923cc1dc7a3Sopenharmony_ci components = 4; 1924cc1dc7a3Sopenharmony_ci copy_method = BGRA8_TO_RGBA8; 1925cc1dc7a3Sopenharmony_ci } 1926cc1dc7a3Sopenharmony_ci // RGBX-unorm8 1927cc1dc7a3Sopenharmony_ci else if ((flags & 0x40) && bitcount == 32 && rmask == 0xFF && gmask == 0xFF00 && bmask == 0xFF0000) 1928cc1dc7a3Sopenharmony_ci { 1929cc1dc7a3Sopenharmony_ci bytes_per_component = 1; 1930cc1dc7a3Sopenharmony_ci components = 4; 1931cc1dc7a3Sopenharmony_ci copy_method = RGBX8_TO_RGBA8; 1932cc1dc7a3Sopenharmony_ci } 1933cc1dc7a3Sopenharmony_ci // BGRX-unorm8 1934cc1dc7a3Sopenharmony_ci else if ((flags & 0x40) && bitcount == 32 && rmask == 0xFF0000 && gmask == 0xFF00 && bmask == 0xFF) 1935cc1dc7a3Sopenharmony_ci { 1936cc1dc7a3Sopenharmony_ci bytes_per_component = 1; 1937cc1dc7a3Sopenharmony_ci components = 4; 1938cc1dc7a3Sopenharmony_ci copy_method = BGRX8_TO_RGBA8; 1939cc1dc7a3Sopenharmony_ci } 1940cc1dc7a3Sopenharmony_ci // RGB-unorm8 1941cc1dc7a3Sopenharmony_ci else if ((flags & 0x40) && bitcount == 24 && rmask == 0xFF && gmask == 0xFF00 && bmask == 0xFF0000) 1942cc1dc7a3Sopenharmony_ci { 1943cc1dc7a3Sopenharmony_ci bytes_per_component = 1; 1944cc1dc7a3Sopenharmony_ci components = 3; 1945cc1dc7a3Sopenharmony_ci copy_method = RGB8_TO_RGBA8; 1946cc1dc7a3Sopenharmony_ci } 1947cc1dc7a3Sopenharmony_ci // BGR-unorm8 1948cc1dc7a3Sopenharmony_ci else if ((flags & 0x40) && bitcount == 24 && rmask == 0xFF0000 && gmask == 0xFF00 && bmask == 0xFF) 1949cc1dc7a3Sopenharmony_ci { 1950cc1dc7a3Sopenharmony_ci bytes_per_component = 1; 1951cc1dc7a3Sopenharmony_ci components = 3; 1952cc1dc7a3Sopenharmony_ci copy_method = BGR8_TO_RGBA8; 1953cc1dc7a3Sopenharmony_ci } 1954cc1dc7a3Sopenharmony_ci // RG-unorm16 1955cc1dc7a3Sopenharmony_ci else if ((flags & 0x40) && bitcount == 16 && rmask == 0xFFFF && gmask == 0xFFFF0000) 1956cc1dc7a3Sopenharmony_ci { 1957cc1dc7a3Sopenharmony_ci bytes_per_component = 2; 1958cc1dc7a3Sopenharmony_ci components = 2; 1959cc1dc7a3Sopenharmony_ci copy_method = RG16_TO_RGBA16F; 1960cc1dc7a3Sopenharmony_ci } 1961cc1dc7a3Sopenharmony_ci // A8L8 1962cc1dc7a3Sopenharmony_ci else if ((flags & 0x20001) == 0x20001 && bitcount == 16 && rmask == 0xFF && amask == 0xFF00) 1963cc1dc7a3Sopenharmony_ci { 1964cc1dc7a3Sopenharmony_ci bytes_per_component = 1; 1965cc1dc7a3Sopenharmony_ci components = 2; 1966cc1dc7a3Sopenharmony_ci copy_method = LA8_TO_RGBA8; 1967cc1dc7a3Sopenharmony_ci } 1968cc1dc7a3Sopenharmony_ci // L8 1969cc1dc7a3Sopenharmony_ci else if ((flags & 0x20000) && bitcount == 8 && rmask == 0xFF) 1970cc1dc7a3Sopenharmony_ci { 1971cc1dc7a3Sopenharmony_ci bytes_per_component = 1; 1972cc1dc7a3Sopenharmony_ci components = 1; 1973cc1dc7a3Sopenharmony_ci copy_method = L8_TO_RGBA8; 1974cc1dc7a3Sopenharmony_ci } 1975cc1dc7a3Sopenharmony_ci // L16 1976cc1dc7a3Sopenharmony_ci else if ((flags & 0x20000) && bitcount == 16 && rmask == 0xFFFF) 1977cc1dc7a3Sopenharmony_ci { 1978cc1dc7a3Sopenharmony_ci bytes_per_component = 2; 1979cc1dc7a3Sopenharmony_ci components = 1; 1980cc1dc7a3Sopenharmony_ci copy_method = L16_TO_RGBA16F; 1981cc1dc7a3Sopenharmony_ci } 1982cc1dc7a3Sopenharmony_ci else 1983cc1dc7a3Sopenharmony_ci { 1984cc1dc7a3Sopenharmony_ci printf("DDS file %s: Non-DXGI format not supported by codec\n", filename); 1985cc1dc7a3Sopenharmony_ci fclose(f); 1986cc1dc7a3Sopenharmony_ci return nullptr; 1987cc1dc7a3Sopenharmony_ci } 1988cc1dc7a3Sopenharmony_ci 1989cc1dc7a3Sopenharmony_ci bitness = bytes_per_component * 8; 1990cc1dc7a3Sopenharmony_ci } 1991cc1dc7a3Sopenharmony_ci 1992cc1dc7a3Sopenharmony_ci // then, load the actual file. 1993cc1dc7a3Sopenharmony_ci uint32_t xstride = bytes_per_component * components * dim_x; 1994cc1dc7a3Sopenharmony_ci uint32_t ystride = xstride * dim_y; 1995cc1dc7a3Sopenharmony_ci uint32_t bytes_of_surface = ystride * dim_z; 1996cc1dc7a3Sopenharmony_ci 1997cc1dc7a3Sopenharmony_ci uint8_t *buf = new uint8_t[bytes_of_surface]; 1998cc1dc7a3Sopenharmony_ci size_t bytes_read = fread(buf, 1, bytes_of_surface, f); 1999cc1dc7a3Sopenharmony_ci fclose(f); 2000cc1dc7a3Sopenharmony_ci if (bytes_read != bytes_of_surface) 2001cc1dc7a3Sopenharmony_ci { 2002cc1dc7a3Sopenharmony_ci delete[] buf; 2003cc1dc7a3Sopenharmony_ci printf("Failed to read file %s\n", filename); 2004cc1dc7a3Sopenharmony_ci return nullptr; 2005cc1dc7a3Sopenharmony_ci } 2006cc1dc7a3Sopenharmony_ci 2007cc1dc7a3Sopenharmony_ci // then transfer data from the surface to our own image-data-structure. 2008cc1dc7a3Sopenharmony_ci astcenc_image *astc_img = alloc_image(bitness, dim_x, dim_y, dim_z); 2009cc1dc7a3Sopenharmony_ci 2010cc1dc7a3Sopenharmony_ci for (unsigned int z = 0; z < dim_z; z++) 2011cc1dc7a3Sopenharmony_ci { 2012cc1dc7a3Sopenharmony_ci for (unsigned int y = 0; y < dim_y; y++) 2013cc1dc7a3Sopenharmony_ci { 2014cc1dc7a3Sopenharmony_ci unsigned int ymod = y_flip ? dim_y - y - 1 : y; 2015cc1dc7a3Sopenharmony_ci unsigned int ydst = ymod; 2016cc1dc7a3Sopenharmony_ci void* dst; 2017cc1dc7a3Sopenharmony_ci 2018cc1dc7a3Sopenharmony_ci if (astc_img->data_type == ASTCENC_TYPE_U8) 2019cc1dc7a3Sopenharmony_ci { 2020cc1dc7a3Sopenharmony_ci uint8_t* data8 = static_cast<uint8_t*>(astc_img->data[z]); 2021cc1dc7a3Sopenharmony_ci dst = static_cast<void*>(&data8[4 * dim_x * ydst]); 2022cc1dc7a3Sopenharmony_ci } 2023cc1dc7a3Sopenharmony_ci else // if (astc_img->data_type == ASTCENC_TYPE_F16) 2024cc1dc7a3Sopenharmony_ci { 2025cc1dc7a3Sopenharmony_ci assert(astc_img->data_type == ASTCENC_TYPE_F16); 2026cc1dc7a3Sopenharmony_ci uint16_t* data16 = static_cast<uint16_t*>(astc_img->data[z]); 2027cc1dc7a3Sopenharmony_ci dst = static_cast<void*>(&data16[4 * dim_x * ydst]); 2028cc1dc7a3Sopenharmony_ci } 2029cc1dc7a3Sopenharmony_ci 2030cc1dc7a3Sopenharmony_ci uint8_t *src = buf + (z * ystride) + (y * xstride); 2031cc1dc7a3Sopenharmony_ci copy_scanline(dst, src, dim_x, copy_method); 2032cc1dc7a3Sopenharmony_ci } 2033cc1dc7a3Sopenharmony_ci } 2034cc1dc7a3Sopenharmony_ci 2035cc1dc7a3Sopenharmony_ci delete[] buf; 2036cc1dc7a3Sopenharmony_ci is_hdr = bitness >= 16; 2037cc1dc7a3Sopenharmony_ci component_count = components; 2038cc1dc7a3Sopenharmony_ci return astc_img; 2039cc1dc7a3Sopenharmony_ci} 2040cc1dc7a3Sopenharmony_ci 2041cc1dc7a3Sopenharmony_ci/** 2042cc1dc7a3Sopenharmony_ci * @brief Save a DDS uncompressed image using a local store routine. 2043cc1dc7a3Sopenharmony_ci * 2044cc1dc7a3Sopenharmony_ci * @param img The source data for the image. 2045cc1dc7a3Sopenharmony_ci * @param filename The name of the file to save. 2046cc1dc7a3Sopenharmony_ci * @param y_flip Should the image be vertically flipped? 2047cc1dc7a3Sopenharmony_ci * 2048cc1dc7a3Sopenharmony_ci * @return @c true if the image saved OK, @c false on error. 2049cc1dc7a3Sopenharmony_ci */ 2050cc1dc7a3Sopenharmony_cistatic bool store_dds_uncompressed_image( 2051cc1dc7a3Sopenharmony_ci const astcenc_image* img, 2052cc1dc7a3Sopenharmony_ci const char* filename, 2053cc1dc7a3Sopenharmony_ci int y_flip 2054cc1dc7a3Sopenharmony_ci) { 2055cc1dc7a3Sopenharmony_ci unsigned int dim_x = img->dim_x; 2056cc1dc7a3Sopenharmony_ci unsigned int dim_y = img->dim_y; 2057cc1dc7a3Sopenharmony_ci unsigned int dim_z = img->dim_z; 2058cc1dc7a3Sopenharmony_ci 2059cc1dc7a3Sopenharmony_ci int bitness = img->data_type == ASTCENC_TYPE_U8 ? 8 : 16; 2060cc1dc7a3Sopenharmony_ci int image_components = (bitness == 16) ? 4 : determine_image_components(img); 2061cc1dc7a3Sopenharmony_ci 2062cc1dc7a3Sopenharmony_ci // DDS-pixel-format structures to use when storing LDR image with 1,2,3 or 4 components. 2063cc1dc7a3Sopenharmony_ci static const dds_pixelformat format_of_image_components[4] = 2064cc1dc7a3Sopenharmony_ci { 2065cc1dc7a3Sopenharmony_ci {32, 0x20000, 0, 8, 0xFF, 0, 0, 0}, // luminance 2066cc1dc7a3Sopenharmony_ci {32, 0x20001, 0, 16, 0xFF, 0, 0, 0xFF00}, // L8A8 2067cc1dc7a3Sopenharmony_ci {32, 0x40, 0, 24, 0xFF, 0xFF00, 0xFF0000, 0}, // RGB8 2068cc1dc7a3Sopenharmony_ci {32, 0x41, 0, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000} // RGBA8 2069cc1dc7a3Sopenharmony_ci }; 2070cc1dc7a3Sopenharmony_ci 2071cc1dc7a3Sopenharmony_ci // DDS-pixel-format structures to use when storing HDR image. 2072cc1dc7a3Sopenharmony_ci static const dds_pixelformat dxt10_diverter = 2073cc1dc7a3Sopenharmony_ci { 2074cc1dc7a3Sopenharmony_ci 32, 4, DX10_MAGIC, 0, 0, 0, 0, 0 2075cc1dc7a3Sopenharmony_ci }; 2076cc1dc7a3Sopenharmony_ci 2077cc1dc7a3Sopenharmony_ci // Header handling; will write: 2078cc1dc7a3Sopenharmony_ci // * DDS magic value 2079cc1dc7a3Sopenharmony_ci // * DDS header 2080cc1dc7a3Sopenharmony_ci // * DDS DX10 header, if the file is floating-point 2081cc1dc7a3Sopenharmony_ci // * pixel data 2082cc1dc7a3Sopenharmony_ci 2083cc1dc7a3Sopenharmony_ci // Main header data 2084cc1dc7a3Sopenharmony_ci dds_header hdr; 2085cc1dc7a3Sopenharmony_ci hdr.size = 124; 2086cc1dc7a3Sopenharmony_ci hdr.flags = 0x100F | (dim_z > 1 ? 0x800000 : 0); 2087cc1dc7a3Sopenharmony_ci hdr.height = dim_y; 2088cc1dc7a3Sopenharmony_ci hdr.width = dim_x; 2089cc1dc7a3Sopenharmony_ci hdr.pitch_or_linear_size = image_components * (bitness / 8) * dim_x; 2090cc1dc7a3Sopenharmony_ci hdr.depth = dim_z; 2091cc1dc7a3Sopenharmony_ci hdr.mipmapcount = 1; 2092cc1dc7a3Sopenharmony_ci for (unsigned int i = 0; i < 11; i++) 2093cc1dc7a3Sopenharmony_ci { 2094cc1dc7a3Sopenharmony_ci hdr.reserved1[i] = 0; 2095cc1dc7a3Sopenharmony_ci } 2096cc1dc7a3Sopenharmony_ci hdr.caps = 0x1000; 2097cc1dc7a3Sopenharmony_ci hdr.caps2 = (dim_z > 1) ? 0x200000 : 0; 2098cc1dc7a3Sopenharmony_ci hdr.caps3 = 0; 2099cc1dc7a3Sopenharmony_ci hdr.caps4 = 0; 2100cc1dc7a3Sopenharmony_ci 2101cc1dc7a3Sopenharmony_ci // Pixel-format data 2102cc1dc7a3Sopenharmony_ci if (bitness == 8) 2103cc1dc7a3Sopenharmony_ci { 2104cc1dc7a3Sopenharmony_ci hdr.ddspf = format_of_image_components[image_components - 1]; 2105cc1dc7a3Sopenharmony_ci } 2106cc1dc7a3Sopenharmony_ci else 2107cc1dc7a3Sopenharmony_ci { 2108cc1dc7a3Sopenharmony_ci hdr.ddspf = dxt10_diverter; 2109cc1dc7a3Sopenharmony_ci } 2110cc1dc7a3Sopenharmony_ci 2111cc1dc7a3Sopenharmony_ci // DX10 data 2112cc1dc7a3Sopenharmony_ci dds_header_dx10 dx10; 2113cc1dc7a3Sopenharmony_ci dx10.dxgi_format = DXGI_FORMAT_R16G16B16A16_FLOAT; 2114cc1dc7a3Sopenharmony_ci dx10.resource_dimension = (dim_z > 1) ? 4 : 3; 2115cc1dc7a3Sopenharmony_ci dx10.misc_flag = 0; 2116cc1dc7a3Sopenharmony_ci dx10.array_size = 1; 2117cc1dc7a3Sopenharmony_ci dx10.reserved = 0; 2118cc1dc7a3Sopenharmony_ci 2119cc1dc7a3Sopenharmony_ci // Collect image data to write 2120cc1dc7a3Sopenharmony_ci uint8_t ***row_pointers8 = nullptr; 2121cc1dc7a3Sopenharmony_ci uint16_t ***row_pointers16 = nullptr; 2122cc1dc7a3Sopenharmony_ci 2123cc1dc7a3Sopenharmony_ci if (bitness == 8) 2124cc1dc7a3Sopenharmony_ci { 2125cc1dc7a3Sopenharmony_ci row_pointers8 = new uint8_t **[dim_z]; 2126cc1dc7a3Sopenharmony_ci row_pointers8[0] = new uint8_t *[dim_y * dim_z]; 2127cc1dc7a3Sopenharmony_ci row_pointers8[0][0] = new uint8_t[dim_x * dim_y * dim_z * image_components]; 2128cc1dc7a3Sopenharmony_ci 2129cc1dc7a3Sopenharmony_ci for (unsigned int z = 1; z < dim_z; z++) 2130cc1dc7a3Sopenharmony_ci { 2131cc1dc7a3Sopenharmony_ci row_pointers8[z] = row_pointers8[0] + dim_y * z; 2132cc1dc7a3Sopenharmony_ci row_pointers8[z][0] = row_pointers8[0][0] + dim_y * dim_z * image_components * z; 2133cc1dc7a3Sopenharmony_ci } 2134cc1dc7a3Sopenharmony_ci 2135cc1dc7a3Sopenharmony_ci for (unsigned int z = 0; z < dim_z; z++) 2136cc1dc7a3Sopenharmony_ci { 2137cc1dc7a3Sopenharmony_ci for (unsigned int y = 1; y < dim_y; y++) 2138cc1dc7a3Sopenharmony_ci { 2139cc1dc7a3Sopenharmony_ci row_pointers8[z][y] = row_pointers8[z][0] + dim_x * image_components * y; 2140cc1dc7a3Sopenharmony_ci } 2141cc1dc7a3Sopenharmony_ci } 2142cc1dc7a3Sopenharmony_ci 2143cc1dc7a3Sopenharmony_ci for (unsigned int z = 0; z < dim_z; z++) 2144cc1dc7a3Sopenharmony_ci { 2145cc1dc7a3Sopenharmony_ci uint8_t* data8 = static_cast<uint8_t*>(img->data[z]); 2146cc1dc7a3Sopenharmony_ci 2147cc1dc7a3Sopenharmony_ci for (unsigned int y = 0; y < dim_y; y++) 2148cc1dc7a3Sopenharmony_ci { 2149cc1dc7a3Sopenharmony_ci int ym = y_flip ? dim_y - y - 1 : y; 2150cc1dc7a3Sopenharmony_ci switch (image_components) 2151cc1dc7a3Sopenharmony_ci { 2152cc1dc7a3Sopenharmony_ci case 1: // single-component, treated as Luminance 2153cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 2154cc1dc7a3Sopenharmony_ci { 2155cc1dc7a3Sopenharmony_ci row_pointers8[z][y][x] = data8[(4 * dim_x * ym) + (4 * x )]; 2156cc1dc7a3Sopenharmony_ci } 2157cc1dc7a3Sopenharmony_ci break; 2158cc1dc7a3Sopenharmony_ci case 2: // two-component, treated as Luminance-Alpha 2159cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 2160cc1dc7a3Sopenharmony_ci { 2161cc1dc7a3Sopenharmony_ci row_pointers8[z][y][2 * x ] = data8[(4 * dim_x * ym) + (4 * x )]; 2162cc1dc7a3Sopenharmony_ci row_pointers8[z][y][2 * x + 1] = data8[(4 * dim_x * ym) + (4 * x + 3)]; 2163cc1dc7a3Sopenharmony_ci } 2164cc1dc7a3Sopenharmony_ci break; 2165cc1dc7a3Sopenharmony_ci case 3: // three-component, treated as RGB 2166cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 2167cc1dc7a3Sopenharmony_ci { 2168cc1dc7a3Sopenharmony_ci row_pointers8[z][y][3 * x ] = data8[(4 * dim_x * ym) + (4 * x )]; 2169cc1dc7a3Sopenharmony_ci row_pointers8[z][y][3 * x + 1] = data8[(4 * dim_x * ym) + (4 * x + 1)]; 2170cc1dc7a3Sopenharmony_ci row_pointers8[z][y][3 * x + 2] = data8[(4 * dim_x * ym) + (4 * x + 2)]; 2171cc1dc7a3Sopenharmony_ci } 2172cc1dc7a3Sopenharmony_ci break; 2173cc1dc7a3Sopenharmony_ci case 4: // four-component, treated as RGBA 2174cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 2175cc1dc7a3Sopenharmony_ci { 2176cc1dc7a3Sopenharmony_ci row_pointers8[z][y][4 * x ] = data8[(4 * dim_x * ym) + (4 * x )]; 2177cc1dc7a3Sopenharmony_ci row_pointers8[z][y][4 * x + 1] = data8[(4 * dim_x * ym) + (4 * x + 1)]; 2178cc1dc7a3Sopenharmony_ci row_pointers8[z][y][4 * x + 2] = data8[(4 * dim_x * ym) + (4 * x + 2)]; 2179cc1dc7a3Sopenharmony_ci row_pointers8[z][y][4 * x + 3] = data8[(4 * dim_x * ym) + (4 * x + 3)]; 2180cc1dc7a3Sopenharmony_ci } 2181cc1dc7a3Sopenharmony_ci break; 2182cc1dc7a3Sopenharmony_ci } 2183cc1dc7a3Sopenharmony_ci } 2184cc1dc7a3Sopenharmony_ci } 2185cc1dc7a3Sopenharmony_ci } 2186cc1dc7a3Sopenharmony_ci else // if bitness == 16 2187cc1dc7a3Sopenharmony_ci { 2188cc1dc7a3Sopenharmony_ci row_pointers16 = new uint16_t **[dim_z]; 2189cc1dc7a3Sopenharmony_ci row_pointers16[0] = new uint16_t *[dim_y * dim_z]; 2190cc1dc7a3Sopenharmony_ci row_pointers16[0][0] = new uint16_t[dim_x * dim_y * dim_z * image_components]; 2191cc1dc7a3Sopenharmony_ci 2192cc1dc7a3Sopenharmony_ci for (unsigned int z = 1; z < dim_z; z++) 2193cc1dc7a3Sopenharmony_ci { 2194cc1dc7a3Sopenharmony_ci row_pointers16[z] = row_pointers16[0] + dim_y * z; 2195cc1dc7a3Sopenharmony_ci row_pointers16[z][0] = row_pointers16[0][0] + dim_y * dim_x * image_components * z; 2196cc1dc7a3Sopenharmony_ci } 2197cc1dc7a3Sopenharmony_ci 2198cc1dc7a3Sopenharmony_ci for (unsigned int z = 0; z < dim_z; z++) 2199cc1dc7a3Sopenharmony_ci { 2200cc1dc7a3Sopenharmony_ci for (unsigned int y = 1; y < dim_y; y++) 2201cc1dc7a3Sopenharmony_ci { 2202cc1dc7a3Sopenharmony_ci row_pointers16[z][y] = row_pointers16[z][0] + dim_x * image_components * y; 2203cc1dc7a3Sopenharmony_ci } 2204cc1dc7a3Sopenharmony_ci } 2205cc1dc7a3Sopenharmony_ci 2206cc1dc7a3Sopenharmony_ci for (unsigned int z = 0; z < dim_z; z++) 2207cc1dc7a3Sopenharmony_ci { 2208cc1dc7a3Sopenharmony_ci uint16_t* data16 = static_cast<uint16_t*>(img->data[z]); 2209cc1dc7a3Sopenharmony_ci 2210cc1dc7a3Sopenharmony_ci for (unsigned int y = 0; y < dim_y; y++) 2211cc1dc7a3Sopenharmony_ci { 2212cc1dc7a3Sopenharmony_ci int ym = y_flip ? dim_y - y - 1: y; 2213cc1dc7a3Sopenharmony_ci switch (image_components) 2214cc1dc7a3Sopenharmony_ci { 2215cc1dc7a3Sopenharmony_ci case 1: // single-component, treated as Luminance 2216cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 2217cc1dc7a3Sopenharmony_ci { 2218cc1dc7a3Sopenharmony_ci row_pointers16[z][y][x] = data16[(4 * dim_x * ym) + (4 * x )]; 2219cc1dc7a3Sopenharmony_ci } 2220cc1dc7a3Sopenharmony_ci break; 2221cc1dc7a3Sopenharmony_ci case 2: // two-component, treated as Luminance-Alpha 2222cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 2223cc1dc7a3Sopenharmony_ci { 2224cc1dc7a3Sopenharmony_ci row_pointers16[z][y][2 * x ] = data16[(4 * dim_x * ym) + (4 * x )]; 2225cc1dc7a3Sopenharmony_ci row_pointers16[z][y][2 * x + 1] = data16[(4 * dim_x * ym) + (4 * x + 3)]; 2226cc1dc7a3Sopenharmony_ci } 2227cc1dc7a3Sopenharmony_ci break; 2228cc1dc7a3Sopenharmony_ci case 3: // three-component, treated as RGB 2229cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 2230cc1dc7a3Sopenharmony_ci { 2231cc1dc7a3Sopenharmony_ci row_pointers16[z][y][3 * x ] = data16[(4 * dim_x * ym) + (4 * x )]; 2232cc1dc7a3Sopenharmony_ci row_pointers16[z][y][3 * x + 1] = data16[(4 * dim_x * ym) + (4 * x + 1)]; 2233cc1dc7a3Sopenharmony_ci row_pointers16[z][y][3 * x + 2] = data16[(4 * dim_x * ym) + (4 * x + 2)]; 2234cc1dc7a3Sopenharmony_ci } 2235cc1dc7a3Sopenharmony_ci break; 2236cc1dc7a3Sopenharmony_ci case 4: // four-component, treated as RGBA 2237cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < dim_x; x++) 2238cc1dc7a3Sopenharmony_ci { 2239cc1dc7a3Sopenharmony_ci row_pointers16[z][y][4 * x ] = data16[(4 * dim_x * ym) + (4 * x )]; 2240cc1dc7a3Sopenharmony_ci row_pointers16[z][y][4 * x + 1] = data16[(4 * dim_x * ym) + (4 * x + 1)]; 2241cc1dc7a3Sopenharmony_ci row_pointers16[z][y][4 * x + 2] = data16[(4 * dim_x * ym) + (4 * x + 2)]; 2242cc1dc7a3Sopenharmony_ci row_pointers16[z][y][4 * x + 3] = data16[(4 * dim_x * ym) + (4 * x + 3)]; 2243cc1dc7a3Sopenharmony_ci } 2244cc1dc7a3Sopenharmony_ci break; 2245cc1dc7a3Sopenharmony_ci } 2246cc1dc7a3Sopenharmony_ci } 2247cc1dc7a3Sopenharmony_ci } 2248cc1dc7a3Sopenharmony_ci } 2249cc1dc7a3Sopenharmony_ci 2250cc1dc7a3Sopenharmony_ci bool retval { true }; 2251cc1dc7a3Sopenharmony_ci uint32_t image_bytes = dim_x * dim_y * dim_z * image_components * (bitness / 8); 2252cc1dc7a3Sopenharmony_ci 2253cc1dc7a3Sopenharmony_ci uint32_t dds_magic = DDS_MAGIC; 2254cc1dc7a3Sopenharmony_ci 2255cc1dc7a3Sopenharmony_ci FILE *wf = fopen(filename, "wb"); 2256cc1dc7a3Sopenharmony_ci if (wf) 2257cc1dc7a3Sopenharmony_ci { 2258cc1dc7a3Sopenharmony_ci void *dataptr = (bitness == 16) ? 2259cc1dc7a3Sopenharmony_ci reinterpret_cast<void*>(row_pointers16[0][0]) : 2260cc1dc7a3Sopenharmony_ci reinterpret_cast<void*>(row_pointers8[0][0]); 2261cc1dc7a3Sopenharmony_ci 2262cc1dc7a3Sopenharmony_ci size_t expected_bytes_written = 4 + sizeof(dds_header) + (bitness > 8 ? sizeof(dds_header_dx10) : 0) + image_bytes; 2263cc1dc7a3Sopenharmony_ci 2264cc1dc7a3Sopenharmony_ci size_t magic_bytes_written = fwrite(&dds_magic, 1, 4, wf); 2265cc1dc7a3Sopenharmony_ci size_t hdr_bytes_written = fwrite(&hdr, 1, sizeof(dds_header), wf); 2266cc1dc7a3Sopenharmony_ci 2267cc1dc7a3Sopenharmony_ci size_t dx10_bytes_written; 2268cc1dc7a3Sopenharmony_ci if (bitness > 8) 2269cc1dc7a3Sopenharmony_ci { 2270cc1dc7a3Sopenharmony_ci dx10_bytes_written = fwrite(&dx10, 1, sizeof(dx10), wf); 2271cc1dc7a3Sopenharmony_ci } 2272cc1dc7a3Sopenharmony_ci else 2273cc1dc7a3Sopenharmony_ci { 2274cc1dc7a3Sopenharmony_ci dx10_bytes_written = 0; 2275cc1dc7a3Sopenharmony_ci } 2276cc1dc7a3Sopenharmony_ci 2277cc1dc7a3Sopenharmony_ci size_t data_bytes_written = fwrite(dataptr, 1, image_bytes, wf); 2278cc1dc7a3Sopenharmony_ci 2279cc1dc7a3Sopenharmony_ci fclose(wf); 2280cc1dc7a3Sopenharmony_ci if (magic_bytes_written + hdr_bytes_written + dx10_bytes_written + data_bytes_written != expected_bytes_written) 2281cc1dc7a3Sopenharmony_ci { 2282cc1dc7a3Sopenharmony_ci retval = false; 2283cc1dc7a3Sopenharmony_ci } 2284cc1dc7a3Sopenharmony_ci } 2285cc1dc7a3Sopenharmony_ci else 2286cc1dc7a3Sopenharmony_ci { 2287cc1dc7a3Sopenharmony_ci retval = false; 2288cc1dc7a3Sopenharmony_ci } 2289cc1dc7a3Sopenharmony_ci 2290cc1dc7a3Sopenharmony_ci if (row_pointers8) 2291cc1dc7a3Sopenharmony_ci { 2292cc1dc7a3Sopenharmony_ci delete[] row_pointers8[0][0]; 2293cc1dc7a3Sopenharmony_ci delete[] row_pointers8[0]; 2294cc1dc7a3Sopenharmony_ci delete[] row_pointers8; 2295cc1dc7a3Sopenharmony_ci } 2296cc1dc7a3Sopenharmony_ci 2297cc1dc7a3Sopenharmony_ci if (row_pointers16) 2298cc1dc7a3Sopenharmony_ci { 2299cc1dc7a3Sopenharmony_ci delete[] row_pointers16[0][0]; 2300cc1dc7a3Sopenharmony_ci delete[] row_pointers16[0]; 2301cc1dc7a3Sopenharmony_ci delete[] row_pointers16; 2302cc1dc7a3Sopenharmony_ci } 2303cc1dc7a3Sopenharmony_ci 2304cc1dc7a3Sopenharmony_ci return retval; 2305cc1dc7a3Sopenharmony_ci} 2306cc1dc7a3Sopenharmony_ci 2307cc1dc7a3Sopenharmony_ci/** 2308cc1dc7a3Sopenharmony_ci * @brief Supported uncompressed image load functions, and their associated file extensions. 2309cc1dc7a3Sopenharmony_ci */ 2310cc1dc7a3Sopenharmony_cistatic const struct 2311cc1dc7a3Sopenharmony_ci{ 2312cc1dc7a3Sopenharmony_ci const char* ending1; 2313cc1dc7a3Sopenharmony_ci const char* ending2; 2314cc1dc7a3Sopenharmony_ci astcenc_image* (*loader_func)(const char*, bool, bool&, unsigned int&); 2315cc1dc7a3Sopenharmony_ci} loader_descs[] { 2316cc1dc7a3Sopenharmony_ci // LDR formats 2317cc1dc7a3Sopenharmony_ci {".png", ".PNG", load_png_with_wuffs}, 2318cc1dc7a3Sopenharmony_ci // HDR formats 2319cc1dc7a3Sopenharmony_ci {".exr", ".EXR", load_image_with_tinyexr }, 2320cc1dc7a3Sopenharmony_ci // Container formats 2321cc1dc7a3Sopenharmony_ci {".ktx", ".KTX", load_ktx_uncompressed_image }, 2322cc1dc7a3Sopenharmony_ci {".dds", ".DDS", load_dds_uncompressed_image }, 2323cc1dc7a3Sopenharmony_ci // Generic catch all; this one must be last in the list 2324cc1dc7a3Sopenharmony_ci { nullptr, nullptr, load_image_with_stb } 2325cc1dc7a3Sopenharmony_ci}; 2326cc1dc7a3Sopenharmony_ci 2327cc1dc7a3Sopenharmony_cistatic const int loader_descr_count = sizeof(loader_descs) / sizeof(loader_descs[0]); 2328cc1dc7a3Sopenharmony_ci 2329cc1dc7a3Sopenharmony_ci/** 2330cc1dc7a3Sopenharmony_ci * @brief Supported uncompressed image store functions, and their associated file extensions. 2331cc1dc7a3Sopenharmony_ci */ 2332cc1dc7a3Sopenharmony_cistatic const struct 2333cc1dc7a3Sopenharmony_ci{ 2334cc1dc7a3Sopenharmony_ci const char *ending1; 2335cc1dc7a3Sopenharmony_ci const char *ending2; 2336cc1dc7a3Sopenharmony_ci int enforced_bitness; 2337cc1dc7a3Sopenharmony_ci bool (*storer_func)(const astcenc_image *output_image, const char *filename, int y_flip); 2338cc1dc7a3Sopenharmony_ci} storer_descs[] { 2339cc1dc7a3Sopenharmony_ci // LDR formats 2340cc1dc7a3Sopenharmony_ci {".bmp", ".BMP", 8, store_bmp_image_with_stb}, 2341cc1dc7a3Sopenharmony_ci {".png", ".PNG", 8, store_png_image_with_stb}, 2342cc1dc7a3Sopenharmony_ci {".tga", ".TGA", 8, store_tga_image_with_stb}, 2343cc1dc7a3Sopenharmony_ci // HDR formats 2344cc1dc7a3Sopenharmony_ci {".exr", ".EXR", 16, store_exr_image_with_tinyexr}, 2345cc1dc7a3Sopenharmony_ci {".hdr", ".HDR", 16, store_hdr_image_with_stb}, 2346cc1dc7a3Sopenharmony_ci // Container formats 2347cc1dc7a3Sopenharmony_ci {".dds", ".DDS", 0, store_dds_uncompressed_image}, 2348cc1dc7a3Sopenharmony_ci {".ktx", ".KTX", 0, store_ktx_uncompressed_image} 2349cc1dc7a3Sopenharmony_ci}; 2350cc1dc7a3Sopenharmony_ci 2351cc1dc7a3Sopenharmony_cistatic const int storer_descr_count = sizeof(storer_descs) / sizeof(storer_descs[0]); 2352cc1dc7a3Sopenharmony_ci 2353cc1dc7a3Sopenharmony_ci/* See header for documentation. */ 2354cc1dc7a3Sopenharmony_ciint get_output_filename_enforced_bitness( 2355cc1dc7a3Sopenharmony_ci const char* filename 2356cc1dc7a3Sopenharmony_ci) { 2357cc1dc7a3Sopenharmony_ci const char *eptr = strrchr(filename, '.'); 2358cc1dc7a3Sopenharmony_ci if (!eptr) 2359cc1dc7a3Sopenharmony_ci { 2360cc1dc7a3Sopenharmony_ci return 0; 2361cc1dc7a3Sopenharmony_ci } 2362cc1dc7a3Sopenharmony_ci 2363cc1dc7a3Sopenharmony_ci for (int i = 0; i < storer_descr_count; i++) 2364cc1dc7a3Sopenharmony_ci { 2365cc1dc7a3Sopenharmony_ci if (strcmp(eptr, storer_descs[i].ending1) == 0 2366cc1dc7a3Sopenharmony_ci || strcmp(eptr, storer_descs[i].ending2) == 0) 2367cc1dc7a3Sopenharmony_ci { 2368cc1dc7a3Sopenharmony_ci return storer_descs[i].enforced_bitness; 2369cc1dc7a3Sopenharmony_ci } 2370cc1dc7a3Sopenharmony_ci } 2371cc1dc7a3Sopenharmony_ci 2372cc1dc7a3Sopenharmony_ci return -1; 2373cc1dc7a3Sopenharmony_ci} 2374cc1dc7a3Sopenharmony_ci 2375cc1dc7a3Sopenharmony_ci/* See header for documentation. */ 2376cc1dc7a3Sopenharmony_ciastcenc_image* load_ncimage( 2377cc1dc7a3Sopenharmony_ci const char* filename, 2378cc1dc7a3Sopenharmony_ci bool y_flip, 2379cc1dc7a3Sopenharmony_ci bool& is_hdr, 2380cc1dc7a3Sopenharmony_ci unsigned int& component_count 2381cc1dc7a3Sopenharmony_ci) { 2382cc1dc7a3Sopenharmony_ci // Get the file extension 2383cc1dc7a3Sopenharmony_ci const char* eptr = strrchr(filename, '.'); 2384cc1dc7a3Sopenharmony_ci if (!eptr) 2385cc1dc7a3Sopenharmony_ci { 2386cc1dc7a3Sopenharmony_ci eptr = filename; 2387cc1dc7a3Sopenharmony_ci } 2388cc1dc7a3Sopenharmony_ci 2389cc1dc7a3Sopenharmony_ci // Scan through descriptors until a matching loader is found 2390cc1dc7a3Sopenharmony_ci for (unsigned int i = 0; i < loader_descr_count; i++) 2391cc1dc7a3Sopenharmony_ci { 2392cc1dc7a3Sopenharmony_ci if (loader_descs[i].ending1 == nullptr 2393cc1dc7a3Sopenharmony_ci || strcmp(eptr, loader_descs[i].ending1) == 0 2394cc1dc7a3Sopenharmony_ci || strcmp(eptr, loader_descs[i].ending2) == 0) 2395cc1dc7a3Sopenharmony_ci { 2396cc1dc7a3Sopenharmony_ci return loader_descs[i].loader_func(filename, y_flip, is_hdr, component_count); 2397cc1dc7a3Sopenharmony_ci } 2398cc1dc7a3Sopenharmony_ci } 2399cc1dc7a3Sopenharmony_ci 2400cc1dc7a3Sopenharmony_ci // Should never reach here - stb_image provides a generic handler 2401cc1dc7a3Sopenharmony_ci return nullptr; 2402cc1dc7a3Sopenharmony_ci} 2403cc1dc7a3Sopenharmony_ci 2404cc1dc7a3Sopenharmony_ci/* See header for documentation. */ 2405cc1dc7a3Sopenharmony_cibool store_ncimage( 2406cc1dc7a3Sopenharmony_ci const astcenc_image* output_image, 2407cc1dc7a3Sopenharmony_ci const char* filename, 2408cc1dc7a3Sopenharmony_ci int y_flip 2409cc1dc7a3Sopenharmony_ci) { 2410cc1dc7a3Sopenharmony_ci const char* eptr = strrchr(filename, '.'); 2411cc1dc7a3Sopenharmony_ci if (!eptr) 2412cc1dc7a3Sopenharmony_ci { 2413cc1dc7a3Sopenharmony_ci eptr = ".ktx"; // use KTX file format if we don't have an ending. 2414cc1dc7a3Sopenharmony_ci } 2415cc1dc7a3Sopenharmony_ci 2416cc1dc7a3Sopenharmony_ci for (int i = 0; i < storer_descr_count; i++) 2417cc1dc7a3Sopenharmony_ci { 2418cc1dc7a3Sopenharmony_ci if (strcmp(eptr, storer_descs[i].ending1) == 0 2419cc1dc7a3Sopenharmony_ci || strcmp(eptr, storer_descs[i].ending2) == 0) 2420cc1dc7a3Sopenharmony_ci { 2421cc1dc7a3Sopenharmony_ci return storer_descs[i].storer_func(output_image, filename, y_flip); 2422cc1dc7a3Sopenharmony_ci } 2423cc1dc7a3Sopenharmony_ci } 2424cc1dc7a3Sopenharmony_ci 2425cc1dc7a3Sopenharmony_ci // Should never reach here - get_output_filename_enforced_bitness should 2426cc1dc7a3Sopenharmony_ci // have acted as a preflight check 2427cc1dc7a3Sopenharmony_ci return false; 2428cc1dc7a3Sopenharmony_ci} 2429cc1dc7a3Sopenharmony_ci 2430cc1dc7a3Sopenharmony_ci/* ============================================================================ 2431cc1dc7a3Sopenharmony_ci ASTC compressed file loading 2432cc1dc7a3Sopenharmony_ci============================================================================ */ 2433cc1dc7a3Sopenharmony_cistruct astc_header 2434cc1dc7a3Sopenharmony_ci{ 2435cc1dc7a3Sopenharmony_ci uint8_t magic[4]; 2436cc1dc7a3Sopenharmony_ci uint8_t block_x; 2437cc1dc7a3Sopenharmony_ci uint8_t block_y; 2438cc1dc7a3Sopenharmony_ci uint8_t block_z; 2439cc1dc7a3Sopenharmony_ci uint8_t dim_x[3]; // dims = dim[0] + (dim[1] << 8) + (dim[2] << 16) 2440cc1dc7a3Sopenharmony_ci uint8_t dim_y[3]; // Sizes are given in texels; 2441cc1dc7a3Sopenharmony_ci uint8_t dim_z[3]; // block count is inferred 2442cc1dc7a3Sopenharmony_ci}; 2443cc1dc7a3Sopenharmony_ci 2444cc1dc7a3Sopenharmony_cistatic const uint32_t ASTC_MAGIC_ID = 0x5CA1AB13; 2445cc1dc7a3Sopenharmony_ci 2446cc1dc7a3Sopenharmony_cistatic unsigned int unpack_bytes( 2447cc1dc7a3Sopenharmony_ci uint8_t a, 2448cc1dc7a3Sopenharmony_ci uint8_t b, 2449cc1dc7a3Sopenharmony_ci uint8_t c, 2450cc1dc7a3Sopenharmony_ci uint8_t d 2451cc1dc7a3Sopenharmony_ci) { 2452cc1dc7a3Sopenharmony_ci return (static_cast<unsigned int>(a) ) + 2453cc1dc7a3Sopenharmony_ci (static_cast<unsigned int>(b) << 8) + 2454cc1dc7a3Sopenharmony_ci (static_cast<unsigned int>(c) << 16) + 2455cc1dc7a3Sopenharmony_ci (static_cast<unsigned int>(d) << 24); 2456cc1dc7a3Sopenharmony_ci} 2457cc1dc7a3Sopenharmony_ci 2458cc1dc7a3Sopenharmony_ci/* See header for documentation. */ 2459cc1dc7a3Sopenharmony_ciint load_cimage( 2460cc1dc7a3Sopenharmony_ci const char* filename, 2461cc1dc7a3Sopenharmony_ci astc_compressed_image& img 2462cc1dc7a3Sopenharmony_ci) { 2463cc1dc7a3Sopenharmony_ci std::ifstream file(filename, std::ios::in | std::ios::binary); 2464cc1dc7a3Sopenharmony_ci if (!file) 2465cc1dc7a3Sopenharmony_ci { 2466cc1dc7a3Sopenharmony_ci print_error("ERROR: File open failed '%s'\n", filename); 2467cc1dc7a3Sopenharmony_ci return 1; 2468cc1dc7a3Sopenharmony_ci } 2469cc1dc7a3Sopenharmony_ci 2470cc1dc7a3Sopenharmony_ci astc_header hdr; 2471cc1dc7a3Sopenharmony_ci file.read(reinterpret_cast<char*>(&hdr), sizeof(astc_header)); 2472cc1dc7a3Sopenharmony_ci if (file.fail()) 2473cc1dc7a3Sopenharmony_ci { 2474cc1dc7a3Sopenharmony_ci print_error("ERROR: File read failed '%s'\n", filename); 2475cc1dc7a3Sopenharmony_ci return 1; 2476cc1dc7a3Sopenharmony_ci } 2477cc1dc7a3Sopenharmony_ci 2478cc1dc7a3Sopenharmony_ci unsigned int magicval = unpack_bytes(hdr.magic[0], hdr.magic[1], hdr.magic[2], hdr.magic[3]); 2479cc1dc7a3Sopenharmony_ci if (magicval != ASTC_MAGIC_ID) 2480cc1dc7a3Sopenharmony_ci { 2481cc1dc7a3Sopenharmony_ci print_error("ERROR: File not recognized '%s'\n", filename); 2482cc1dc7a3Sopenharmony_ci return 1; 2483cc1dc7a3Sopenharmony_ci } 2484cc1dc7a3Sopenharmony_ci 2485cc1dc7a3Sopenharmony_ci // Ensure these are not zero to avoid div by zero 2486cc1dc7a3Sopenharmony_ci unsigned int block_x = astc::max(static_cast<unsigned int>(hdr.block_x), 1u); 2487cc1dc7a3Sopenharmony_ci unsigned int block_y = astc::max(static_cast<unsigned int>(hdr.block_y), 1u); 2488cc1dc7a3Sopenharmony_ci unsigned int block_z = astc::max(static_cast<unsigned int>(hdr.block_z), 1u); 2489cc1dc7a3Sopenharmony_ci 2490cc1dc7a3Sopenharmony_ci unsigned int dim_x = unpack_bytes(hdr.dim_x[0], hdr.dim_x[1], hdr.dim_x[2], 0); 2491cc1dc7a3Sopenharmony_ci unsigned int dim_y = unpack_bytes(hdr.dim_y[0], hdr.dim_y[1], hdr.dim_y[2], 0); 2492cc1dc7a3Sopenharmony_ci unsigned int dim_z = unpack_bytes(hdr.dim_z[0], hdr.dim_z[1], hdr.dim_z[2], 0); 2493cc1dc7a3Sopenharmony_ci 2494cc1dc7a3Sopenharmony_ci if (dim_x == 0 || dim_y == 0 || dim_z == 0) 2495cc1dc7a3Sopenharmony_ci { 2496cc1dc7a3Sopenharmony_ci print_error("ERROR: Image header corrupt '%s'\n", filename); 2497cc1dc7a3Sopenharmony_ci return 1; 2498cc1dc7a3Sopenharmony_ci } 2499cc1dc7a3Sopenharmony_ci 2500cc1dc7a3Sopenharmony_ci unsigned int xblocks = (dim_x + block_x - 1) / block_x; 2501cc1dc7a3Sopenharmony_ci unsigned int yblocks = (dim_y + block_y - 1) / block_y; 2502cc1dc7a3Sopenharmony_ci unsigned int zblocks = (dim_z + block_z - 1) / block_z; 2503cc1dc7a3Sopenharmony_ci 2504cc1dc7a3Sopenharmony_ci size_t data_size = xblocks * yblocks * zblocks * 16; 2505cc1dc7a3Sopenharmony_ci uint8_t *buffer = new uint8_t[data_size]; 2506cc1dc7a3Sopenharmony_ci 2507cc1dc7a3Sopenharmony_ci file.read(reinterpret_cast<char*>(buffer), data_size); 2508cc1dc7a3Sopenharmony_ci if (file.fail()) 2509cc1dc7a3Sopenharmony_ci { 2510cc1dc7a3Sopenharmony_ci print_error("ERROR: Image data size exceeded file size '%s'\n", filename); 2511cc1dc7a3Sopenharmony_ci delete[] buffer; 2512cc1dc7a3Sopenharmony_ci return 1; 2513cc1dc7a3Sopenharmony_ci } 2514cc1dc7a3Sopenharmony_ci 2515cc1dc7a3Sopenharmony_ci img.data = buffer; 2516cc1dc7a3Sopenharmony_ci img.data_len = data_size; 2517cc1dc7a3Sopenharmony_ci img.block_x = block_x; 2518cc1dc7a3Sopenharmony_ci img.block_y = block_y; 2519cc1dc7a3Sopenharmony_ci img.block_z = block_z; 2520cc1dc7a3Sopenharmony_ci img.dim_x = dim_x; 2521cc1dc7a3Sopenharmony_ci img.dim_y = dim_y; 2522cc1dc7a3Sopenharmony_ci img.dim_z = dim_z; 2523cc1dc7a3Sopenharmony_ci return 0; 2524cc1dc7a3Sopenharmony_ci} 2525cc1dc7a3Sopenharmony_ci 2526cc1dc7a3Sopenharmony_ci/* See header for documentation. */ 2527cc1dc7a3Sopenharmony_ciint store_cimage( 2528cc1dc7a3Sopenharmony_ci const astc_compressed_image& img, 2529cc1dc7a3Sopenharmony_ci const char* filename 2530cc1dc7a3Sopenharmony_ci) { 2531cc1dc7a3Sopenharmony_ci astc_header hdr; 2532cc1dc7a3Sopenharmony_ci hdr.magic[0] = ASTC_MAGIC_ID & 0xFF; 2533cc1dc7a3Sopenharmony_ci hdr.magic[1] = (ASTC_MAGIC_ID >> 8) & 0xFF; 2534cc1dc7a3Sopenharmony_ci hdr.magic[2] = (ASTC_MAGIC_ID >> 16) & 0xFF; 2535cc1dc7a3Sopenharmony_ci hdr.magic[3] = (ASTC_MAGIC_ID >> 24) & 0xFF; 2536cc1dc7a3Sopenharmony_ci 2537cc1dc7a3Sopenharmony_ci hdr.block_x = static_cast<uint8_t>(img.block_x); 2538cc1dc7a3Sopenharmony_ci hdr.block_y = static_cast<uint8_t>(img.block_y); 2539cc1dc7a3Sopenharmony_ci hdr.block_z = static_cast<uint8_t>(img.block_z); 2540cc1dc7a3Sopenharmony_ci 2541cc1dc7a3Sopenharmony_ci hdr.dim_x[0] = img.dim_x & 0xFF; 2542cc1dc7a3Sopenharmony_ci hdr.dim_x[1] = (img.dim_x >> 8) & 0xFF; 2543cc1dc7a3Sopenharmony_ci hdr.dim_x[2] = (img.dim_x >> 16) & 0xFF; 2544cc1dc7a3Sopenharmony_ci 2545cc1dc7a3Sopenharmony_ci hdr.dim_y[0] = img.dim_y & 0xFF; 2546cc1dc7a3Sopenharmony_ci hdr.dim_y[1] = (img.dim_y >> 8) & 0xFF; 2547cc1dc7a3Sopenharmony_ci hdr.dim_y[2] = (img.dim_y >> 16) & 0xFF; 2548cc1dc7a3Sopenharmony_ci 2549cc1dc7a3Sopenharmony_ci hdr.dim_z[0] = img.dim_z & 0xFF; 2550cc1dc7a3Sopenharmony_ci hdr.dim_z[1] = (img.dim_z >> 8) & 0xFF; 2551cc1dc7a3Sopenharmony_ci hdr.dim_z[2] = (img.dim_z >> 16) & 0xFF; 2552cc1dc7a3Sopenharmony_ci 2553cc1dc7a3Sopenharmony_ci std::ofstream file(filename, std::ios::out | std::ios::binary); 2554cc1dc7a3Sopenharmony_ci if (!file) 2555cc1dc7a3Sopenharmony_ci { 2556cc1dc7a3Sopenharmony_ci print_error("ERROR: File open failed '%s'\n", filename); 2557cc1dc7a3Sopenharmony_ci return 1; 2558cc1dc7a3Sopenharmony_ci } 2559cc1dc7a3Sopenharmony_ci 2560cc1dc7a3Sopenharmony_ci file.write(reinterpret_cast<char*>(&hdr), sizeof(astc_header)); 2561cc1dc7a3Sopenharmony_ci file.write(reinterpret_cast<char*>(img.data), img.data_len); 2562cc1dc7a3Sopenharmony_ci return 0; 2563cc1dc7a3Sopenharmony_ci} 2564